| @@ -148,6 +148,10 @@ public class ShiroConfig { | |||
| // filterChainDefinitionMap.put("/role/**", "corsFilter,token"); | |||
| //商场初始化init | |||
| // filterChainDefinitionMap.put("/wxProjectConfig/**", "anon"); | |||
| // filterChainDefinitionMap.put("/goodsCategory/**", "anon"); | |||
| // filterChainDefinitionMap.put("/wxCoupon/goods/**", "anon"); | |||
| // //test | |||
| // filterChainDefinitionMap.put("/merchantPoi/spuSync", "anon"); | |||
| @@ -0,0 +1,38 @@ | |||
| package com.iformall.controller.basic; | |||
| import com.iformall.annotation.SystemControllerLog; | |||
| import com.iformall.annotation.TenantIgnore; | |||
| import com.iformall.common.ResultData; | |||
| import com.iformall.controller.base.BaseController; | |||
| import com.iformall.service.TtGoodsCategoryService; | |||
| import io.swagger.annotations.ApiImplicitParams; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| /** | |||
| * @author gongbiao | |||
| */ | |||
| @RestController | |||
| @RequestMapping("goodsCategory") | |||
| public class TtGoodsCategoryController extends BaseController { | |||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
| @Autowired | |||
| private TtGoodsCategoryService ttGoodsCategoryService; | |||
| @TenantIgnore | |||
| @ApiOperation("分页列表接口") | |||
| @GetMapping("treeList") | |||
| @ApiImplicitParams({}) | |||
| @SystemControllerLog(description = "列表") | |||
| public ResultData treeList() { | |||
| logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::treeList"); | |||
| return new ResultData(ttGoodsCategoryService.findTreeList()); | |||
| } | |||
| } | |||
| @@ -137,80 +137,80 @@ public class TtMerchantPoiController extends BaseController { | |||
| return ttMerchantPoiService.supplierQuery(getTenantInfo(),id); | |||
| } | |||
| @ApiOperation("获取商品可用的POI") | |||
| @GetMapping("/findPoi") | |||
| @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true) | |||
| @SystemControllerLog(description = "查询") | |||
| public ResultData findPoi(Long couponChannelId) { | |||
| logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::findPoi"); | |||
| if(couponChannelId == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| return ttMerchantPoiService.findPoi(getTenantInfo(),couponChannelId); | |||
| } | |||
| @ApiOperation("商品同步") | |||
| @PostMapping("spuSync") | |||
| @SystemControllerLog(description = "商品同步") | |||
| public ResultData spuSync(@RequestBody Map<String, String> param) { | |||
| logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuSync"); | |||
| String couponChannelIdStr = param.get("couponChannelId"); | |||
| Long couponChannelId = null; | |||
| try{ | |||
| couponChannelId = Long.parseLong(couponChannelIdStr); | |||
| }catch(Exception e){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR); | |||
| } | |||
| if(couponChannelId == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| // String merchantIdStr = param.get("merchantIds"); | |||
| // List<Long> merchantIds = new ArrayList<>(); | |||
| // @ApiOperation("获取商品可用的POI") | |||
| // @GetMapping("/findPoi") | |||
| // @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true) | |||
| // @SystemControllerLog(description = "查询") | |||
| // public ResultData findPoi(Long couponChannelId) { | |||
| // logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::findPoi"); | |||
| // if(couponChannelId == null){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| // } | |||
| // return ttMerchantPoiService.findPoi(getTenantInfo(),couponChannelId); | |||
| // } | |||
| // @ApiOperation("商品同步") | |||
| // @PostMapping("spuSync") | |||
| // @SystemControllerLog(description = "商品同步") | |||
| // public ResultData spuSync(@RequestBody Map<String, String> param) { | |||
| // logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuSync"); | |||
| // String couponChannelIdStr = param.get("couponChannelId"); | |||
| // Long couponChannelId = null; | |||
| // try{ | |||
| // List<String> strings = Arrays.asList(merchantIdStr.split(",")); | |||
| // merchantIds = strings.stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList()); | |||
| // couponChannelId = Long.parseLong(couponChannelIdStr); | |||
| // }catch(Exception e){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR); | |||
| // } | |||
| // if(merchantIds == null || merchantIds.size() == 0){ | |||
| // if(couponChannelId == null){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| // } | |||
| return ttMerchantPoiService.spuSync(getTenantInfo(),couponChannelId,null); | |||
| } | |||
| @ApiOperation("商品同步查询") | |||
| @GetMapping("spuGet") | |||
| @SystemControllerLog(description = "商品同步查询") | |||
| public ResultData spuGet(Long couponChannelId) { | |||
| logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuGet"); | |||
| if(couponChannelId == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| return ttMerchantPoiService.spuGet(getTenantInfo(),couponChannelId); | |||
| } | |||
| @ApiOperation("商品状态同步") | |||
| @PostMapping("spuStatusSync") | |||
| @SystemControllerLog(description = "商品状态同步") | |||
| public ResultData spuStatusSync(@RequestBody Map<String, Long> param) { | |||
| logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuStatusSync"); | |||
| Long couponChannelId = param.get("couponChannelId"); | |||
| if(couponChannelId == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| return ttMerchantPoiService.spuStatusSync(getTenantInfo(),couponChannelId); | |||
| } | |||
| @ApiOperation("商品库存同步") | |||
| @PostMapping("spuStockSync") | |||
| @SystemControllerLog(description = "商品库存同步") | |||
| public ResultData spuStockSync(@RequestBody Map<String, Long> param) { | |||
| logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuStockSync"); | |||
| Long couponChannelId = param.get("couponChannelId"); | |||
| if(couponChannelId == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| return ttMerchantPoiService.spuStockSync(getTenantInfo(),couponChannelId); | |||
| } | |||
| //// String merchantIdStr = param.get("merchantIds"); | |||
| //// List<Long> merchantIds = new ArrayList<>(); | |||
| //// try{ | |||
| //// List<String> strings = Arrays.asList(merchantIdStr.split(",")); | |||
| //// merchantIds = strings.stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList()); | |||
| //// }catch(Exception e){ | |||
| //// return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR); | |||
| //// } | |||
| //// if(merchantIds == null || merchantIds.size() == 0){ | |||
| //// return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| //// } | |||
| // return ttMerchantPoiService.spuSync(getTenantInfo(),couponChannelId,null); | |||
| // } | |||
| // @ApiOperation("商品同步查询") | |||
| // @GetMapping("spuGet") | |||
| // @SystemControllerLog(description = "商品同步查询") | |||
| // public ResultData spuGet(Long couponChannelId) { | |||
| // logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuGet"); | |||
| // if(couponChannelId == null){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| // } | |||
| // return ttMerchantPoiService.spuGet(getTenantInfo(),couponChannelId); | |||
| // } | |||
| // | |||
| // @ApiOperation("商品状态同步") | |||
| // @PostMapping("spuStatusSync") | |||
| // @SystemControllerLog(description = "商品状态同步") | |||
| // public ResultData spuStatusSync(@RequestBody Map<String, Long> param) { | |||
| // logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuStatusSync"); | |||
| // Long couponChannelId = param.get("couponChannelId"); | |||
| // if(couponChannelId == null){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| // } | |||
| // return ttMerchantPoiService.spuStatusSync(getTenantInfo(),couponChannelId); | |||
| // } | |||
| // | |||
| // @ApiOperation("商品库存同步") | |||
| // @PostMapping("spuStockSync") | |||
| // @SystemControllerLog(description = "商品库存同步") | |||
| // public ResultData spuStockSync(@RequestBody Map<String, Long> param) { | |||
| // logger.debug("[" + getIpAddr() + "] TtMerchantPoiController::spuStockSync"); | |||
| // Long couponChannelId = param.get("couponChannelId"); | |||
| // if(couponChannelId == null){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| // } | |||
| // return ttMerchantPoiService.spuStockSync(getTenantInfo(),couponChannelId); | |||
| // } | |||
| } | |||
| @@ -10,10 +10,13 @@ import com.iformall.controller.base.BaseController; | |||
| import com.iformall.domain.po.*; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.vo.WxWeappInfo; | |||
| import com.iformall.douyin.pay.TtPayService; | |||
| import com.iformall.douyin.payv2.request.CallBackSettingsRequest; | |||
| import com.iformall.enums.*; | |||
| import com.iformall.service.*; | |||
| import com.iformall.shiro.PasswordHelper; | |||
| import com.iformall.utils.Constant; | |||
| import com.iformall.utils.MaUtil; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| @@ -94,6 +97,9 @@ public class WxProjectConfigController extends BaseController { | |||
| @Autowired | |||
| private WechatWebProperties wechatWebProperties; | |||
| @Autowired | |||
| private MaUtil maUtil; | |||
| @Autowired | |||
| @Qualifier("openRedisTemplate") | |||
| RedisTemplate<String, String> openRedisTemplate; | |||
| @@ -774,4 +780,74 @@ public class WxProjectConfigController extends BaseController { | |||
| } | |||
| } | |||
| @ApiOperation("获取抖音支付2.0 回调接口配置") | |||
| @GetMapping("/ttcallback/query/settings") | |||
| @SystemControllerLog(description = "") | |||
| @TenantIgnore | |||
| public ResultData ttcallbackQuerySettings(String appid) { | |||
| logger.debug("[" + getIpAddr() + "] WxProjectConfigController::ttcallbackQuerySettings"); | |||
| try { | |||
| WxAppinfo appinfo = wxAppinfoService.getByAppId(appid); | |||
| if(appinfo == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的小程序"); | |||
| } | |||
| if(!EnumAppPlat.TOUTIAO.getCode().equals(appinfo.getPlat()) || !EnumAppType.C.getCode().equals(appinfo.getType())){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"该小程序不支持"); | |||
| } | |||
| WxPayAccount payAccount = wxPayAccountService.getById(appinfo.getPayId()); | |||
| if(payAccount == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的支付数据"); | |||
| } | |||
| TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); | |||
| CallBackSettingsRequest callBackSettingsRequest = ttPayService.querySettings(); | |||
| return new ResultData(callBackSettingsRequest); | |||
| }catch (Exception e){ | |||
| logger.error(e.getMessage(),e); | |||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR); | |||
| } | |||
| } | |||
| @ApiOperation("配置抖音支付2.0 回调接口") | |||
| @PostMapping("/ttcallback/settings") | |||
| @SystemControllerLog(description = "商场集团-更新") | |||
| @TenantIgnore | |||
| public ResultData ttcallbackSettings(@RequestBody Map<String, String> map) { | |||
| logger.debug("[" + getIpAddr() + "] WxProjectConfigController::ttcallbackSettings"); | |||
| String appid = map.get("appid"); | |||
| String create_order_callback = map.get("create_order_callback"); | |||
| String refund_callback = map.get("refund_callback"); | |||
| String delivery_qrcode_redirect = map.get("delivery_qrcode_redirect"); | |||
| if(StringUtils.isBlank(appid) || StringUtils.isBlank(create_order_callback) | |||
| || StringUtils.isBlank(refund_callback)){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| try { | |||
| WxAppinfo appinfo = wxAppinfoService.getByAppId(appid); | |||
| if(appinfo == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的小程序"); | |||
| } | |||
| if(!EnumAppPlat.TOUTIAO.getCode().equals(appinfo.getPlat()) || !EnumAppType.C.getCode().equals(appinfo.getType())){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"该小程序不支持"); | |||
| } | |||
| WxPayAccount payAccount = wxPayAccountService.getById(appinfo.getPayId()); | |||
| if(payAccount == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的支付数据"); | |||
| } | |||
| TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); | |||
| CallBackSettingsRequest request = new CallBackSettingsRequest(); | |||
| request.setCreateOrderCallback(create_order_callback); | |||
| request.setRefundCallback(refund_callback); | |||
| request.setDeliveryQrcodeRedirect(delivery_qrcode_redirect); | |||
| boolean b = ttPayService.callbackSettings(request); | |||
| if(b){ | |||
| return new ResultData(); | |||
| }else{ | |||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR); | |||
| } | |||
| }catch (Exception e){ | |||
| logger.error(e.getMessage(),e); | |||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,184 @@ | |||
| package com.iformall.controller.market; | |||
| import com.iformall.annotation.SystemControllerLog; | |||
| import com.iformall.common.ErrorCode; | |||
| import com.iformall.common.ResultData; | |||
| import com.iformall.controller.base.BaseController; | |||
| import com.iformall.domain.po.WxCoupon; | |||
| import com.iformall.domain.po.base.BaseEntity; | |||
| import com.iformall.domain.vo.TtCouponChannelVo; | |||
| import com.iformall.domain.vo.TtCouponVo; | |||
| import com.iformall.douyin.web.bean.GoodsTemplateGet; | |||
| import com.iformall.enums.*; | |||
| import com.iformall.service.*; | |||
| 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.lang3.StringUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| @RestController | |||
| @RequestMapping("ttgoods") | |||
| @Api(description = "抖音商品库") | |||
| public class TtCouponGoodsController extends BaseController { | |||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
| @Autowired | |||
| private WxCouponService wxCouponService; | |||
| @Autowired | |||
| private TtCouponGoodsService ttCouponGoodsService; | |||
| @Autowired | |||
| private TtMerchantPoiService ttMerchantPoiService; | |||
| @Autowired | |||
| private TtGoodsCategoryService ttGoodsCategoryService; | |||
| @ApiOperation("分页列表接口") | |||
| @GetMapping("couponList") | |||
| @ApiImplicitParams({ | |||
| @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), | |||
| @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) | |||
| @SystemControllerLog(description = "-列表") | |||
| public ResultData couponList(@ModelAttribute TtCouponVo ttCouponVo, Integer pageNum, Integer pageSize) { | |||
| logger.debug("[" + getIpAddr() + "] WxCouponController::couponList"); | |||
| if (ttCouponVo == null) ttCouponVo = new TtCouponVo(); | |||
| ttCouponVo.updateTenantInfo(getTenantInfo()); | |||
| ttCouponVo.setType(EnumCouponType.COUPON_DOUYIN.getCode()); | |||
| if(StringUtils.isNotBlank(ttCouponVo.getSortColumn())){ | |||
| String coryColumn = "c."+ttCouponVo.getSortColumns(); | |||
| ttCouponVo.setSortColumns(coryColumn); | |||
| ttCouponVo.setSortColumn(null); | |||
| }else{ | |||
| ttCouponVo.setSortColumns(BaseEntity.SortField.CCreateDate_DESC, BaseEntity.SortField.CId_DESC); | |||
| } | |||
| if (ttCouponVo.getStatus() != null && ttCouponVo.getStatus() == -1) | |||
| ttCouponVo.setStatus(null); | |||
| return ttCouponGoodsService.couponList(ttCouponVo, pageNum, pageSize); | |||
| } | |||
| @ApiOperation("分页列表接口") | |||
| @GetMapping("channelList") | |||
| @ApiImplicitParams({ | |||
| @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), | |||
| @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) | |||
| @SystemControllerLog(description = "-列表") | |||
| public ResultData channelList(@ModelAttribute TtCouponChannelVo ttChannelVo, Integer pageNum, Integer pageSize) { | |||
| logger.debug("[" + getIpAddr() + "] WxCouponController::channelList"); | |||
| if (ttChannelVo == null) ttChannelVo = new TtCouponChannelVo(); | |||
| ttChannelVo.updateTenantInfo(getTenantInfo()); | |||
| ttChannelVo.setTargetAd(EnumCouponChannelType.COUPON_CHANNEL_ID_DOUYIN_LIST.getCode()); | |||
| if(null == ttChannelVo.getSourceType()){ | |||
| ttChannelVo.setSourceType(EnumCouponSourceType.COUPONSource_Admin.getCode()); | |||
| } | |||
| if(StringUtils.isNotBlank(ttChannelVo.getSortColumn())){ | |||
| String coryColumn = "cc."+ttChannelVo.getSortColumns(); | |||
| ttChannelVo.setSortColumns(coryColumn); | |||
| ttChannelVo.setSortColumn(null); | |||
| }else{ | |||
| ttChannelVo.setSortColumns(BaseEntity.SortField.CCUpdateDate_DESC); | |||
| } | |||
| return ttCouponGoodsService.channelList(ttChannelVo, pageNum, pageSize); | |||
| } | |||
| @ApiOperation("根据类目获取商品模板") | |||
| @GetMapping("getTemplate") | |||
| @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true) | |||
| @SystemControllerLog(description = "根据类目获取商品模板") | |||
| public ResultData getGoodsTemplate(Long couponId,Integer categoryId,Integer productType) { | |||
| logger.debug("[" + getIpAddr() + "] WxCouponController::getGoodsTemplate"); | |||
| if(productType == null){ | |||
| productType = 1; | |||
| } | |||
| if(couponId == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| WxCoupon coupon = wxCouponService.getAttrsById(couponId, getTenantInfo().getTenantId()); | |||
| if(coupon == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| try { | |||
| GoodsTemplateGet goodsTemplateGet = ttMerchantPoiService.getTtWebService(getTenantInfo()).getGoodsService().templateGet(categoryId, productType); | |||
| ttGoodsCategoryService.adminIsShow(goodsTemplateGet); | |||
| ttGoodsCategoryService.handTemplate(goodsTemplateGet,coupon); | |||
| return new ResultData(goodsTemplateGet); | |||
| } catch (WxErrorException e) { | |||
| e.printStackTrace(); | |||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR.getCode(),e.getMessage()); | |||
| } | |||
| } | |||
| @ApiOperation("提交审核") | |||
| @PostMapping("product/save") | |||
| @SystemControllerLog(description = "提交审核") | |||
| public ResultData productSave(@RequestBody WxCoupon wxCoupon) { | |||
| if (wxCoupon.getId() == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| WxCoupon coupon = wxCouponService.getById(wxCoupon.getId(), getTenantInfo().getTenantId()); | |||
| if(coupon == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||
| } | |||
| try { | |||
| return ttCouponGoodsService.productSave(coupon); | |||
| } catch (Exception e) { | |||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR.getCode(),e.getMessage()); | |||
| } | |||
| } | |||
| @ApiOperation("实时查询审核状态") | |||
| @GetMapping("product/draft") | |||
| @SystemControllerLog(description = "实时查询审核状态") | |||
| public ResultData productDraft(Long id) { | |||
| if (id == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| return ttCouponGoodsService.productDraftGet(getTenantInfo(),id); | |||
| } | |||
| @ApiOperation("实时查询线上商品状态") | |||
| @GetMapping("product/online") | |||
| @SystemControllerLog(description = "实时查询审核状态") | |||
| public ResultData productOnline(Long id) { | |||
| if (id == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| return ttCouponGoodsService.productOnlineGet(getTenantInfo(),id); | |||
| } | |||
| @ApiOperation("实时同步上下架状态") | |||
| @GetMapping("product/operate") | |||
| @SystemControllerLog(description = "实时同步上下架状态") | |||
| public ResultData productOperate(Long id) { | |||
| if (id == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| return ttCouponGoodsService.productOperate(getTenantInfo(),id); | |||
| } | |||
| @ApiOperation("实时同步库存") | |||
| @GetMapping("product/stock/sync") | |||
| @SystemControllerLog(description = "实时同步库存") | |||
| public ResultData productStockSync(Long id) { | |||
| if (id == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| return ttCouponGoodsService.productStockSync(getTenantInfo(),id); | |||
| } | |||
| } | |||
| @@ -52,6 +52,7 @@ public class WxCouponChannelController extends BaseController { | |||
| @Autowired | |||
| @Qualifier("objectCommonRedisTemplate") | |||
| RedisTemplate<String, Object> redisTemplate; | |||
| @ApiOperation("分页列表接口") | |||
| @GetMapping("list") | |||
| @@ -98,6 +99,23 @@ public class WxCouponChannelController extends BaseController { | |||
| return resultData; | |||
| } | |||
| @ApiOperation("预审核上架") | |||
| @PostMapping("updateOnline") | |||
| @SystemControllerLog(description = "预审核上架") | |||
| public ResultData updateOnline(@RequestBody WxCouponChannel wxCouponChannel) { | |||
| wxCouponChannel.updateTenantInfo(getTenantInfo()); | |||
| if (wxCouponChannel.getId() == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| ResultData resultData = wxCouponChannelService.updateOnline(wxCouponChannel); | |||
| if(resultData.code == 200){ | |||
| CouponCacheUtils.removeCouponChannelCache(redisTemplate, wxCouponChannel.getId()); | |||
| CouponCacheUtils.removeDouyinLivePageCache(redisTemplate, wxCouponChannel.getTenantId(), null, null); | |||
| } | |||
| return resultData; | |||
| } | |||
| @ApiOperation("根据id查询接口") | |||
| @@ -13,14 +13,12 @@ import com.iformall.domain.po.WxCouponChannel; | |||
| import com.iformall.domain.po.WxCouponPassword; | |||
| import com.iformall.domain.po.WxPayAccount; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.vo.TtCouponVo; | |||
| 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 +27,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; | |||
| @@ -227,6 +226,45 @@ public class WxCouponController extends BaseController { | |||
| return result; | |||
| } | |||
| @ApiOperation("根据id更新接口") | |||
| @PostMapping("continueAdd") | |||
| @SystemControllerLog(description = "继续添加") | |||
| public ResultData continueAdd(@RequestBody WxCoupon wxCoupon) { | |||
| logger.debug("[" + getIpAddr() + "] WxCouponController::update"); | |||
| if (wxCoupon.getId() == null) { | |||
| return new ResultData(ResultData.ERROR, "缺少id"); | |||
| } | |||
| if(wxCoupon.getProductType() == null || wxCoupon.getCategoryId() == null){ | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "缺少必要参数"); | |||
| } | |||
| wxCoupon.updateTenantInfo(getTenantInfo()); | |||
| if(EnumDelFlag.YES.getCode().equals(wxCoupon.getIsDel())){ | |||
| WxCouponChannel query = new WxCouponChannel(); | |||
| query.updateTenantInfo(wxCoupon); | |||
| query.setCouponId(wxCoupon.getId()); | |||
| query.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode()); | |||
| if (CollectionUtils.isNotEmpty(wxCouponChannelMapper.findList(query))) { | |||
| return new ResultData(ResultData.ERROR, "有活动正在上架,请先下架。"); | |||
| } | |||
| } | |||
| WxCoupon coupon = wxCouponService.getById(wxCoupon.getId(),wxCoupon.getTenantId()); | |||
| if (null == coupon) { | |||
| return new ResultData(ResultData.ERROR, "券未查询到。"+wxCoupon.getId()); | |||
| } | |||
| coupon.setProductType(wxCoupon.getProductType()); | |||
| coupon.setCategoryId(wxCoupon.getCategoryId()); | |||
| coupon.setProductAttrs(wxCoupon.getProductAttrs()); | |||
| coupon.setSkuAttrs(wxCoupon.getSkuAttrs()); | |||
| ResultData result = wxCouponService.updateTtProduct(coupon); | |||
| CouponCacheUtils.removeCouponCache(redisTemplate, wxCoupon.getId()); | |||
| CouponCacheUtils.removeCouponMerchantCache(redisTemplate, wxCoupon.getId()); | |||
| return result; | |||
| } | |||
| @ApiOperation("根据id更新库存及有效期接口") | |||
| @PostMapping("updateStokeAndValidDate") | |||
| @SystemControllerLog(description = "券投放-库存/有效期更新") | |||
| @@ -123,7 +123,7 @@ public class WxCouponOrderController extends BaseController { | |||
| wxCouponOrder.getMerchantName().isEmpty()) { | |||
| wxCouponOrder.setMerchantName(null); | |||
| } | |||
| wxCouponOrderService.exportData(wxCouponOrder, request, response); | |||
| wxCouponOrderService.exportData(false,wxCouponOrder, request, response); | |||
| } | |||
| } | |||
| @@ -7,24 +7,17 @@ import com.iformall.common.Result; | |||
| import com.iformall.common.ResultData; | |||
| import com.iformall.controller.base.BaseController; | |||
| import com.iformall.domain.dto.OrderSaveDto; | |||
| import com.iformall.domain.po.WxCUser; | |||
| import com.iformall.domain.po.WxCUserBasicInfo; | |||
| import com.iformall.domain.po.WxCoupon; | |||
| import com.iformall.domain.po.WxCouponChannel; | |||
| import com.iformall.domain.po.WxOrder; | |||
| import com.iformall.domain.po.*; | |||
| import com.iformall.domain.po.base.BaseEntity; | |||
| import com.iformall.domain.vo.WxMerchantSubsidyVo; | |||
| import com.iformall.domain.vo.WxOrderQueryVo; | |||
| import com.iformall.enums.*; | |||
| import com.iformall.exception.MallinkException; | |||
| import com.iformall.service.WxCUserBasicInfoService; | |||
| import com.iformall.service.WxCUserService; | |||
| import com.iformall.service.WxCouponChannelService; | |||
| import com.iformall.service.WxCouponService; | |||
| import com.iformall.service.WxOrderService; | |||
| import com.iformall.service.*; | |||
| import com.iformall.service.order.OrderFactory; | |||
| import com.iformall.service.order.entity.WxComposeOrder; | |||
| import com.iformall.utils.MaUtil; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiImplicitParam; | |||
| import io.swagger.annotations.ApiImplicitParams; | |||
| @@ -54,6 +47,9 @@ public class WxOrderController extends BaseController { | |||
| @Autowired | |||
| private WxOrderService wxOrderService; | |||
| @Autowired | |||
| private WxPayOrderService wxPayOrderService; | |||
| @Autowired | |||
| private WxCUserService wxCUserService; | |||
| @@ -62,7 +58,7 @@ public class WxOrderController extends BaseController { | |||
| @Autowired | |||
| private WxCUserBasicInfoService wxCUserBasicInfoService; | |||
| @Autowired | |||
| OrderFactory orderFactory; | |||
| @@ -193,7 +189,7 @@ public class WxOrderController extends BaseController { | |||
| // 免费券 | |||
| WxComposeOrder composeOrder = orderFactory.getOrderAdapterService(EnumComposeOrder.SINGLE.getCode()).createDBMainOrder(coupon, user, 0, EnumPayWay.PAY_WAY_NOT_UNPAY_CREDIT); | |||
| order = wxOrderService.saveFreeOrderForCoupon(new Date(),false,composeOrder,user, coupon, 1, | |||
| wxCouponChannel, orderSaveDto.getFormId(), null,EnumPayWay.PAY_WAY_NOT_UNPAY_CREDIT, | |||
| wxCouponChannel, orderSaveDto.getFormId(), null,null,EnumPayWay.PAY_WAY_NOT_UNPAY_CREDIT, | |||
| EnumOrderShopingType.ONLINE_PURCHASE.getCode(),null); | |||
| return new ResultData(order); | |||
| } catch (MallinkException e) { | |||
| @@ -268,4 +264,19 @@ public class WxOrderController extends BaseController { | |||
| } | |||
| @ApiOperation("查看抖音订单状态") | |||
| @GetMapping("/ttorderQuery") | |||
| @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true) | |||
| @SystemControllerLog(description = "订单管理-id查询") | |||
| public ResultData ttorderQuery(Long id) { | |||
| logger.debug("[" + getIpAddr() + "] WxOrderController::ttorderQuery"); | |||
| // WxBatchOrder wxBatchOrder = wxOrderService.getWxBatchOrder(getTenantInfo(), id); | |||
| // if(wxBatchOrder == null || !EnumPayWay.PAY_WAY_TT.getCode().equals(wxBatchOrder.getPayVendor())){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_ERROR.getCode(), "订单未找到或不支持"); | |||
| // } | |||
| return new ResultData(wxPayOrderService.ttorderQuery(getTenantInfo(),id)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,303 @@ | |||
| ALTER TABLE wx_order_0 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_1 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_2 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_3 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_4 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_5 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_6 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_7 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_8 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_9 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_10 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_11 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_12 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_13 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_14 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_15 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_16 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_17 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_18 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_19 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_20 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_21 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_22 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_23 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_24 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_25 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_26 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_27 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_28 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_29 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_30 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_31 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_32 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_33 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_34 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_35 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_36 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_37 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_38 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_39 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_40 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_41 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_42 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_43 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_44 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_45 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_46 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_47 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_48 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_49 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_50 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_51 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_52 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_53 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_54 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_55 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_56 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_57 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_58 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_59 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_60 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_61 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_62 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_63 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_64 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_65 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_66 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_67 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_68 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_69 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_70 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_71 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_72 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_73 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_74 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_75 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_76 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_77 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_78 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_79 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_80 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_81 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_82 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_83 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_84 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_85 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_86 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_87 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_88 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_89 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_90 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_91 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_92 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_93 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_94 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_95 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_96 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_97 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_98 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_order_99 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_0 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_1 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_2 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_3 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_4 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_5 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_6 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_7 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_8 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_9 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_10 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_11 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_12 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_13 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_14 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_15 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_16 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_17 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_18 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_19 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_20 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_21 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_22 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_23 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_24 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_25 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_26 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_27 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_28 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_29 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_30 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_31 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_32 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_33 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_34 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_35 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_36 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_37 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_38 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_39 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_40 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_41 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_42 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_43 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_44 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_45 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_46 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_47 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_48 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_49 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_50 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_51 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_52 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_53 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_54 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_55 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_56 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_57 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_58 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_59 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_60 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_61 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_62 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_63 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_64 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_65 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_66 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_67 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_68 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_69 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_70 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_71 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_72 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_73 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_74 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_75 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_76 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_77 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_78 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_79 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_80 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_81 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_82 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_83 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_84 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_85 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_86 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_87 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_88 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_89 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_90 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_91 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_92 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_93 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_94 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_95 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_96 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_97 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_98 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_coupon_order_99 ADD COLUMN `ext_param` VARCHAR(1000) COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_0 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_1 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_2 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_3 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_4 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_5 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_6 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_7 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_8 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_9 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_10 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_11 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_12 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_13 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_14 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_15 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_16 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_17 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_18 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_19 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_20 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_21 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_22 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_23 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_24 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_25 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_26 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_27 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_28 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_29 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_30 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_31 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_32 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_33 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_34 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_35 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_36 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_37 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_38 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_39 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_40 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_41 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_42 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_43 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_44 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_45 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_46 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_47 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_48 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_49 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_50 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_51 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_52 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_53 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_54 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_55 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_56 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_57 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_58 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_59 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_60 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_61 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_62 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_63 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_64 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_65 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_66 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_67 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_68 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_69 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_70 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_71 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_72 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_73 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_74 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_75 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_76 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_77 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_78 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_79 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_80 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_81 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_82 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_83 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_84 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_85 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_86 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_87 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_88 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_89 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_90 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_91 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_92 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_93 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_94 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_95 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_96 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_97 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_98 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| ALTER TABLE wx_batch_order_99 ADD COLUMN `ext_param` text COMMENT '额外参数,用于第三方平台'; | |||
| @@ -0,0 +1,505 @@ | |||
| ALTER TABLE `mallink`.`tt_coupon_channel_poi` | |||
| ADD COLUMN `coupon_channel_id` bigint(20) NOT NULL AFTER `parent_tenant_id`; | |||
| ALTER TABLE `mallink`.`wx_coupon_0` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_1` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_2` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_3` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_4` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_5` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_6` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_7` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_8` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_9` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_10` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_11` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_12` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_13` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_14` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_15` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_16` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_17` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_18` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_19` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_20` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_21` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_22` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_23` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_24` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_25` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_26` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_27` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_28` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_29` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_30` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_31` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_32` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_33` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_34` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_35` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_36` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_37` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_38` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_39` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_40` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_41` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_42` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_43` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_44` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_45` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_46` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_47` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_48` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_49` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_50` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_51` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_52` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_53` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_54` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_55` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_56` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_57` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_58` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_59` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_60` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_61` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_62` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_63` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_64` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_65` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_66` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_67` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_68` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_69` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_70` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_71` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_72` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_73` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_74` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_75` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_76` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_77` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_78` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_79` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_80` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_81` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_82` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_83` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_84` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_85` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_86` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_87` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_88` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_89` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_90` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_91` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_92` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_93` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_94` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_95` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_96` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_97` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_98` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| ALTER TABLE `mallink`.`wx_coupon_99` | |||
| ADD COLUMN `product_type` tinyint(1) DEFAULT 1 COMMENT 'EnumTtProductType' AFTER `gift_list`, | |||
| ADD COLUMN `category_id` int(11) DEFAULT NULL COMMENT '商品类目' AFTER `product_type`, | |||
| ADD COLUMN `product_attrs` json COMMENT '商品动态属性' AFTER `category_id`, | |||
| ADD COLUMN `sku_attrs` json COMMENT 'sku动态属性' AFTER `product_attrs`; | |||
| @@ -0,0 +1,4 @@ | |||
| INSERT INTO `mallink`.`mall_permission`(`id`, `name`, `parent_id`, `available`, `permission`, `resource_type`, `module_color`, `module_color_num`, `url`, `icon`, `version_type`, `sort`) VALUES (676, '抖音宣传页', 605, 'Y', NULL, 1, NULL, NULL, 'ttxcList', NULL, 0, 671); | |||
| UPDATE `mallink`.`mall_sale_type` SET `menus` = '[1, 2, 4, 5, 6, 50, 105, 110, 201, 205, 202, 211, 212, 221, 222, 223, 251, 409, 410, 411, 416, 500, 502, 504, 505, 506, 507, 508, 511, 512, 521, 522, 523, 531, 532, 591, 592, 595, 602, 605, 606, 607, 610, 647, 671, 675, 676, 680, 711, 901, 902, 904, 907, 60702]' WHERE `id` = 11; | |||
| @@ -2,6 +2,7 @@ package com.iformall.controller; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.github.pagehelper.PageInfo; | |||
| import com.iformall.annotation.AuthIgnore; | |||
| import com.iformall.annotation.RedisCache; | |||
| import com.iformall.common.ErrorCode; | |||
| import com.iformall.common.Result; | |||
| @@ -35,6 +36,9 @@ import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.concurrent.TimeUnit; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| @RestController | |||
| @RequestMapping("/api/couponOrder") | |||
| @Api(description = "卡券相关接口") | |||
| @@ -463,4 +467,43 @@ public class WxCouponOrderController extends BaseController { | |||
| } | |||
| return new ResultData(); | |||
| } | |||
| @ApiOperation(value = "B端核销列表链接") | |||
| @GetMapping("/getVerifiedExportUrl") | |||
| public ResultData getVerifiedExportUrl(@ModelAttribute WxCouponOrderBVo wxCouponOrder) { | |||
| //只有B端管理员才能操作这个 | |||
| WxMerchantBUser buser = this.getLoginBUser(); | |||
| WxMerchant merchantQ= new WxMerchant(); | |||
| merchantQ.updateTenantInfo(buser); | |||
| merchantQ.setId(buser.getMerchantId()); | |||
| WxMerchant merchant = wxMerchantService.findOne(merchantQ); | |||
| if (!(buser.getPhone().equals(merchant.getLinkPhone()))) { | |||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR.getCode(),"只有商户管理员才能进行此操作"); | |||
| } | |||
| if (wxCouponOrder == null) wxCouponOrder = new WxCouponOrderBVo(); | |||
| wxCouponOrder.updateTenantInfo(getTenantInfo()); | |||
| StringBuffer sb = new StringBuffer("/api/couponOrder/unLogin/verifiedExport?verifyMerchantId=").append(buser.getMerchantId()) | |||
| .append("&tenantId="+wxCouponOrder.getTenantId()); | |||
| if (null != wxCouponOrder.getVerifyStartDate()) { | |||
| sb.append("&verifyStartDate=").append(wxCouponOrder.getVerifyStartDate()); | |||
| } | |||
| if (null != wxCouponOrder.getVerifyEndDate()) { | |||
| sb.append("&verifyEndDate=").append(wxCouponOrder.getVerifyEndDate()); | |||
| } | |||
| return new ResultData(sb.toString()); | |||
| } | |||
| @GetMapping("/unLogin/verifiedExport") | |||
| @AuthIgnore | |||
| public void verifiedExport(@ModelAttribute WxCouponOrderBVo wxCouponOrder, HttpServletRequest request, HttpServletResponse response) { | |||
| logger.debug("[" + getIpAddr() + "] WxCouponOrderController::exportData"); | |||
| if (wxCouponOrder == null) { | |||
| return; | |||
| } | |||
| wxCouponOrder.setStartDate(DateUtils.stringToDate("2022-01-01 00:00:00",DateUtils.DATE_TIME_PATTERN)); | |||
| wxCouponOrder.setEndDate(DateUtils.stringToDate("2122-01-01 00:00:00",DateUtils.DATE_TIME_PATTERN)); | |||
| wxCouponOrderService.exportData(true,wxCouponOrder, request, response); | |||
| } | |||
| } | |||
| @@ -110,7 +110,11 @@ public class WxCouponController extends BaseController { | |||
| if (null == coupon) { | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannel找不到coupon" + couponChannelId); | |||
| } | |||
| if(EnumCouponType.COUPON_GIFT.getCode().equals(coupon.getType())){ | |||
| WxCoupon attrsById = couponService.getAttrsById(couponChannel.getCouponId(), couponChannel.getTenantId()); | |||
| coupon.setProductAttrs(attrsById.getProductAttrs()); | |||
| coupon.setSkuAttrs(attrsById.getSkuAttrs()); | |||
| if(EnumCouponType.COUPON_GIFT.getCode().equals(coupon.getType())){ | |||
| WxCoupon couponQ = new WxCoupon(); | |||
| couponQ.updateTenantInfo(coupon); | |||
| List<Long> longs = JSON.parseArray(coupon.getGiftList(), Long.class); | |||
| @@ -103,7 +103,7 @@ public class WxCouponPasswordController extends BaseController { | |||
| try { | |||
| WxComposeOrder composeOrder = orderFactory.getOrderAdapterService(EnumComposeOrder.SINGLE.getCode()).createDBMainOrder(coupon, member, 0, payWay); | |||
| WxOrder order = orderService.saveFreeOrderForCoupon(new Date(),false,composeOrder,member, coupon, 1, | |||
| null, formId, couponPassword.getId(),payWay, | |||
| null, formId, couponPassword.getId(),null,payWay, | |||
| EnumOrderShopingType.ONLINE_PURCHASE.getCode(),null); | |||
| } catch (MallinkException e) { | |||
| setCouponPasswordStatus(couponPassword, EnumCouponPasswordStatus.getEnum(pwdStatus)); | |||
| @@ -1,6 +1,10 @@ | |||
| package com.iformall.controller; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONArray; | |||
| 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; | |||
| import com.iformall.annotation.AuthIgnore; | |||
| import com.iformall.annotation.TenantIgnore; | |||
| @@ -10,20 +14,28 @@ import com.iformall.common.Result; | |||
| import com.iformall.common.ResultData; | |||
| import com.iformall.domain.dto.OrderComposeSaveDto; | |||
| 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.base.TenantEntity; | |||
| 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.service.pay.entity.PayExtraParam; | |||
| import com.iformall.utils.Constant; | |||
| import com.iformall.utils.IPUtil; | |||
| import com.iformall.utils.MaUtil; | |||
| import com.iformall.utils.RedisLock; | |||
| import io.swagger.annotations.Api; | |||
| @@ -38,10 +50,8 @@ import org.springframework.beans.factory.annotation.Qualifier; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import java.util.ArrayList; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import java.util.*; | |||
| @RestController | |||
| @RequestMapping("/api/order/") | |||
| @@ -58,6 +68,9 @@ public class WxOrderController extends BaseController { | |||
| @Autowired | |||
| private WxCouponService wxCouponService; | |||
| @Autowired | |||
| private CUserServiceFactory cuserFactory; | |||
| @Autowired | |||
| private WxCUserBasicInfoService wxCUserBasicInfoService; | |||
| @@ -79,6 +92,9 @@ public class WxOrderController extends BaseController { | |||
| @Autowired | |||
| private OrderFactory orderFactory; | |||
| @Autowired | |||
| private MaUtil maUtil; | |||
| @Autowired | |||
| @Qualifier("couponDetailRedisTemplate") | |||
| RedisTemplate<String, WxCouponCVo> cdRedisTemplate; | |||
| @@ -122,7 +138,7 @@ public class WxOrderController extends BaseController { | |||
| } catch (Exception e) { | |||
| return new ResultData(Result.ERROR,e.getMessage()); | |||
| } | |||
| return wxOrderService.composeSaveOrder(false,EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,orderSaveDto,memberId,EnumPayWay.PAY_WAY_WECHAT,getTenantInfo()); | |||
| return wxOrderService.composeSaveOrder(false,EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,orderSaveDto,memberId,getPayWay(),getTenantInfo()); | |||
| } | |||
| @ApiOperation(value = "单个券单个订单,卡(分账导致无法批量下单)、拼团,砍价用", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") | |||
| @@ -142,6 +158,208 @@ public class WxOrderController extends BaseController { | |||
| list.add(dto); | |||
| return wxOrderService.composeSaveOrder(false,EnumComposeOrder.SINGLE,list,memberId,getPayWay(),getTenantInfo()); | |||
| } | |||
| @AuthIgnore | |||
| @ApiOperation(value = "抖音支付2.0与下单回调推送订单", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") | |||
| @PostMapping("douyinPushOrder") | |||
| public Map<String,Object> douyinPushOrder(HttpServletRequest request) { | |||
| Map<String, Object> map = new HashMap(); | |||
| SignatureHeader header = new SignatureHeader(); | |||
| header.setTimeStamp(request.getHeader("Byte-Timestamp")); | |||
| header.setNonce(request.getHeader("Byte-Nonce-Str")); | |||
| header.setSigned(request.getHeader("Byte-Signature")); | |||
| logger.info("支付2.0预下单回调---header{}"+header.toString()); | |||
| String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); | |||
| logger.info("支付2.0预下单回调---body{}"+body); | |||
| try { | |||
| JSONObject jsonObject = JSONObject.parseObject(body); | |||
| String msg = jsonObject.getString("msg"); | |||
| JSONObject msgObject = JSONObject.parseObject(msg); | |||
| String app_id = msgObject.getString("app_id"); | |||
| String open_id = msgObject.getString("open_id"); | |||
| //透传字段 | |||
| Map<String,String> couponMap = new HashMap<>(); | |||
| try{ | |||
| String cp_extra = msgObject.getString("cp_extra"); | |||
| if(StringUtils.isBlank(cp_extra)){ | |||
| map.put("err_no",ErrorCode.SYS_PARAMETER_NOT_NULL.getCode()); | |||
| map.put("err_tips","缺少透传字段"); | |||
| return map; | |||
| } | |||
| couponMap = JSONObject.parseObject(cp_extra, Map.class); | |||
| }catch(Exception e){ | |||
| } | |||
| if(couponMap.isEmpty()){ | |||
| map.put("err_no",ErrorCode.SYS_PARAMETER_NOT_NULL.getCode()); | |||
| map.put("err_tips","透传字段格式不正确"); | |||
| return map; | |||
| } | |||
| //验证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; | |||
| } | |||
| TenantEntity tenantEntity = new TenantEntity(); | |||
| tenantEntity.updateTenantInfo(appinfo); | |||
| //验证用户 | |||
| Long memberId = null; | |||
| TtCUser cuser = (TtCUser) cuserFactory.getCUserService(EnumAppPlat.TOUTIAO).getByOpenId(open_id, tenantEntity.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; | |||
| } | |||
| 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<PlatPushOrderSaveDto> list = new ArrayList<>(); | |||
| for (CreateOrderCallback.Good good:createOrderCallback.getGoods()) { | |||
| PlatPushOrderSaveDto dto = new PlatPushOrderSaveDto(); | |||
| dto.setCouponChannelId(Long.parseLong(couponMap.get(good.getGoodsId()))); | |||
| dto.setCount(good.getQuantity()); | |||
| dto.setExtParam(JSON.toJSONString(good.getItemOrderInfoList())); | |||
| list.add(dto); | |||
| } | |||
| ResultData resultData = wxOrderService.platPushSaveOrder(true, EnumComposeOrder.ONE_NUMBER_ORDER_BATCH, allExtParam.toJSONString(), list, memberId, EnumPayWay.PAY_WAY_TT, tenantEntity); | |||
| logger.info("resultData{}"+JSON.toJSONString(resultData)); | |||
| if(resultData.code == 200){ | |||
| WxComposeOrder order = (WxComposeOrder) resultData.data; | |||
| Map<String, Object> data = new HashMap<>(); | |||
| data.put("out_order_no",order.getMainOrderId().toString()); | |||
| // data.put("pay_expire_seconds",300); | |||
| data.put("order_entry_schema",wxOrderService.getOrderEntrySchema(order.getMainOrderId())); | |||
| // List<Map<String,Object>> goodsValid = new ArrayList<>(); | |||
| // for (Long couponChannelId:order.getCouponChannelMap().keySet()) { | |||
| // Map<String,Object> goodsValidMap = new HashMap<>(); | |||
| // WxCouponChannel couponChannel = order.getCouponChannelMap().get(couponChannelId); | |||
| // goodsValidMap.put("goods_id",couponChannel.getTtSpuId()); | |||
| // 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); | |||
| logger.info("resultData{}"+JSON.toJSONString(map)); | |||
| 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; | |||
| } | |||
| } | |||
| // @ApiOperation(value = "更新订单状态", notes = "{\"payOrderId\":\"string\",\"composeOrderId\":\"string\",\"status\":integer,\"reason\":\"string\"}") | |||
| // @PostMapping("/updatePayOrder") | |||
| // public ResultData updatePayOrder(@RequestBody Map<String, Object> paramMap) { | |||
| // logger.info("/api/pay/updatePayOrder" + paramMap.toString()); | |||
| // String orderIdStr = (String) paramMap.get("composeOrderId"); | |||
| // if (StringUtils.isBlank(orderIdStr)) { | |||
| // logger.info("orderId不能为空: " + paramMap.toString()); | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空"); | |||
| // } | |||
| // Long orderId = 0L; | |||
| // try { | |||
| // orderId = Long.valueOf(orderIdStr); | |||
| // } catch (NumberFormatException e) { | |||
| // logger.error("orderId参数不正确: " + paramMap.toString() + ", e:" + e.getMessage()); | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId参数不正确"); | |||
| // } | |||
| // | |||
| // WxBatchOrder batchOrder = wxOrderService.getWxBatchOrder(getTenantInfo(),orderId); | |||
| // if(batchOrder == null){ | |||
| // return new ResultData(ErrorCode.SYS_PARAMETER_ERROR.getCode(), "未找到订单"); | |||
| // } | |||
| // | |||
| // WxPayOrder payOrder = new WxPayOrder(); | |||
| // payOrder.setOrderId(orderId); | |||
| // payOrder.updateTenantInfo(getTenantInfo()); | |||
| // payOrder.setPayVendor(getPayWay().getCode()); | |||
| // payOrder.setComposeOrder(batchOrder.getOrderType()); | |||
| // | |||
| // try { | |||
| // WxPayOrder byObj = wxPayOrderService.getByObj(payOrder); | |||
| // if(byObj != null){ | |||
| // return new ResultData(Result.SUCCESS, "支付状态更新成功"); | |||
| // }else{ | |||
| // | |||
| // | |||
| // WxComposeOrder composeOrder = orderFactory.getOrderAdapterService(payOrder.getComposeOrder()).getComposeOrder(payOrder.getOrderId(), payOrder.getTenantId()); | |||
| // | |||
| // WxAppinfo appInfo = wxAppinfoService.getCAppInfo(payOrder, EnumPayWay.getEnum(payOrder.getPayVendor()).getPlat()); | |||
| // //WxCUser user = getUser(); | |||
| // //WxAppinfo appInfo = getAppInfo(user.getAppId()); | |||
| // if (null == appInfo) { | |||
| // return new ResultData(ErrorCode.PAY_ORDER_ERROR, "当前支付类型["+payOrder.getPayVendor()+"]找不到C端appInfo"); | |||
| // } | |||
| // WxPayAccount payAccount = wxPayAccountService.getById(appInfo.getPayId()); | |||
| // try { | |||
| // WxPayOrder wo = wxPayOrderService.handleWxOrderQuery(payOrder, composeOrder,appInfo, payAccount, IdWorker.get(),false); | |||
| // if (null != wo) { | |||
| // return new ResultData(Result.SUCCESS, "支付状态更新成功", composeOrder); | |||
| // } | |||
| // }catch(MallinkException e) { | |||
| // //已经同步了微信的支付状态,表示已经更新 | |||
| // return new ResultData(Result.SUCCESS, "支付状态更新成功", composeOrder); | |||
| // } | |||
| // | |||
| // return new ResultData(ErrorCode.PAY_ORDER_ERROR, "查询微信订单支付状态失败,请稍后!"); | |||
| // } | |||
| // } catch (MallinkException e) { | |||
| // logger.error("支付状态更新失败2: " + payOrder.toString() + ", e:" + e.getMessage(),e); | |||
| // return new ResultData(e.getErrorCode(), e.getMessage()); | |||
| // } catch (Exception e) { | |||
| // logger.error("支付状态更新失败3: " + payOrder.toString() + ", e:" + e.getMessage(),e); | |||
| // return new ResultData(ErrorCode.PAY_ORDER_ERROR, "支付状态更新失败3: " + payOrder.toString() + ", e:" + e.getMessage()); | |||
| // } | |||
| // } | |||
| @ApiOperation(value = "取消订单", notes = "{\"orderId\":\"string\"}") | |||
| @PostMapping("cancel") | |||
| @@ -169,7 +387,6 @@ public class WxOrderController extends BaseController { | |||
| if (null != payOrder) { | |||
| WxComposeOrder composeOrder = orderFactory.getOrderAdapterService(payOrder.getComposeOrder()).getComposeOrder(payOrder.getOrderId(), payOrder.getTenantId()); | |||
| //查询微信订单状态并更新 | |||
| boolean hasCompleted = wxPayOrderService.hasCompleted(composeOrder,payOrder); | |||
| if (!hasCompleted) { | |||
| WxAppinfo appInfo = wxAppinfoService.getCAppInfo(payOrder, EnumPayWay.getEnum(payOrder.getPayVendor()).getPlat()); | |||
| @@ -714,5 +931,25 @@ public class WxOrderController extends BaseController { | |||
| // | |||
| // return openId; | |||
| // } | |||
| @AuthIgnore | |||
| @ApiOperation(value = "抖音支付2.0与退款回调推送订单", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") | |||
| @PostMapping("douyinRefundOrder") | |||
| public Map<String,Object> douyinRefundOrder(HttpServletRequest request) { | |||
| SignatureHeader header = new SignatureHeader(); | |||
| header.setTimeStamp(request.getHeader("Byte-Timestamp")); | |||
| header.setNonce(request.getHeader("Byte-Nonce-Str")); | |||
| header.setSigned(request.getHeader("Byte-Signature")); | |||
| logger.info("支付2.0预下单回调---header{}"+header.toString()); | |||
| String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); | |||
| logger.info("支付2.0预下单回调---body{}"+body); | |||
| Map<String, Object> map = new HashMap(); | |||
| map.put("err_no",1001); | |||
| map.put("err_tips","未找到支付信息"); | |||
| return map; | |||
| } | |||
| } | |||
| @@ -100,10 +100,11 @@ public class WxPayOrderController extends BaseController { | |||
| return new ResultData(ErrorCode.USER_IS_NOT_MEMBER.getCode(), "暂未成为会员,请授权手机号"); | |||
| } | |||
| return _create(orderIdStr,composeOrderType,user.getUserId(),getPayWay(),user.getAppId(),new PayExtraParam("openId",user.getOpenId()),request); | |||
| return _create(orderIdStr,composeOrderType,user.getUserId(),getPayWay(),user.getAppId(),new PayExtraParam("openId",user.getOpenId()),true,request); | |||
| } | |||
| private ResultData _create(String orderIdStr,String composeOrderType,Long userId, EnumPayWay payWay,String appId,PayExtraParam parm,HttpServletRequest request) { | |||
| private ResultData _create(String orderIdStr,String composeOrderType,Long userId, EnumPayWay payWay, | |||
| String appId,PayExtraParam parm,boolean isCreatePay,HttpServletRequest request) { | |||
| WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoService.getById(userId,getFinalTenantId()); | |||
| if ( null == wxCUserBasicInfo) { | |||
| logger.error("会员用户不存在."+userId); | |||
| @@ -128,7 +129,7 @@ public class WxPayOrderController extends BaseController { | |||
| try { | |||
| record.setIp(IPUtil.getIpAddr(request)); | |||
| record.setComposeOrder(Integer.parseInt(composeOrderType)); | |||
| return wxPayOrderService.createPayOrder(appInfo, wxCUserBasicInfo, record, payWay,parm); | |||
| return wxPayOrderService.createPayOrder(appInfo, wxCUserBasicInfo, record, payWay,parm,isCreatePay); | |||
| } catch (MallinkException e) { | |||
| logger.error("payment wechat, order create error, req 2: " + record.toString() + ", e:" + e.getMessage(),e); | |||
| return new ResultData(e.getErrorCode(), e.getMessage()); | |||
| @@ -138,6 +139,30 @@ public class WxPayOrderController extends BaseController { | |||
| } | |||
| } | |||
| @RequestMapping(value = "/ttcreatev2", method = RequestMethod.POST) | |||
| public ResultData _ttcreatev2(@RequestBody Map<String, String> paramMap, HttpServletRequest request) throws Exception { | |||
| logger.info("/api/pay/create" + paramMap.toString()); | |||
| String orderIdStr = paramMap.get("orderId"); | |||
| if (StringUtils.isBlank(orderIdStr)) { | |||
| logger.info("orderId不能为空: " + paramMap.toString()); | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空"); | |||
| } | |||
| String composeOrderType = paramMap.get("composeOrderType"); | |||
| if (StringUtils.isBlank(composeOrderType)) { | |||
| logger.info("composeOrderType不能为空: " + paramMap.toString()); | |||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "composeOrderType不能为空"); | |||
| } | |||
| CUser user = getCUser(); | |||
| if (!user.basicInfoIs()) { | |||
| logger.error("暂未成为会员,请授权手机号"); | |||
| return new ResultData(ErrorCode.USER_IS_NOT_MEMBER.getCode(), "暂未成为会员,请授权手机号"); | |||
| } | |||
| return _create(orderIdStr,composeOrderType,user.getUserId(),getPayWay(),user.getAppId(),new PayExtraParam("openId",user.getOpenId()),false,request); | |||
| } | |||
| @ApiOperation(value = "更新支付订单状态", notes = "{\"payOrderId\":\"string\",\"composeOrderId\":\"string\",\"status\":integer,\"reason\":\"string\"}") | |||
| @PostMapping("/updatePayOrder") | |||
| public ResultData updatePayOrder(@RequestBody Map<String, Object> paramMap) { | |||
| @@ -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"); | |||
| @@ -219,7 +219,7 @@ public class JinMaoController extends BaseController { | |||
| try { | |||
| inputStream = request.getInputStream(); | |||
| String paramStr = IOUtils.toString(inputStream, "utf-8"); | |||
| logger.info("dfh heartBeat: {}",paramStr); | |||
| // logger.info("dfh heartBeat: {}",paramStr); | |||
| if (StringUtils.isBlank(paramStr)) { | |||
| generateHeartBeatResult(response,"unvalid param", "参数不能为空paramStr",currentTime); | |||
| return ; | |||
| @@ -2,25 +2,28 @@ package com.iformall.controller.callback; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||
| import com.iformall.common.ErrorCode; | |||
| import com.iformall.common.ResultData; | |||
| import com.iformall.controller.base.BaseController; | |||
| import com.iformall.domain.po.WxAppinfo; | |||
| import com.iformall.domain.po.WxBatchOrder; | |||
| import com.iformall.domain.po.WxPayAccount; | |||
| import com.iformall.domain.po.WxPayOrder; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.po.msg.FmInsideNotifyRefundSuccessMsg; | |||
| import com.iformall.douyin.pay.DouYinPayHelper; | |||
| import com.iformall.douyin.pay.TtPayService; | |||
| import com.iformall.douyin.payv2.result.CreateOrderCallback; | |||
| import com.iformall.enums.*; | |||
| import com.iformall.interceptor.BodyReaderHttpServletRequestWrapper; | |||
| import com.iformall.mq.MqBaseProducer; | |||
| import com.iformall.service.WxAppinfoService; | |||
| import com.iformall.service.WxPayAccountService; | |||
| import com.iformall.service.WxPayOrderService; | |||
| import com.iformall.service.WxRefundOrderService; | |||
| import com.iformall.service.*; | |||
| import com.iformall.service.order.OrderFactory; | |||
| import com.iformall.service.order.entity.WxComposeOrder; | |||
| import com.iformall.service.pay.PayServiceFactory; | |||
| import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; | |||
| import com.iformall.utils.MaUtil; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| @@ -28,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| @@ -50,6 +54,9 @@ public class TtPayController extends BaseController { | |||
| @Autowired | |||
| private WxPayOrderService wxPayOrderService; | |||
| @Autowired | |||
| private WxOrderService wxOrderService; | |||
| @Autowired | |||
| private OrderFactory orderFactory; | |||
| @@ -59,6 +66,9 @@ public class TtPayController extends BaseController { | |||
| @Autowired | |||
| private MqBaseProducer mqBaseProducer; | |||
| @Autowired | |||
| private MaUtil maUtil; | |||
| /** | |||
| * timestamp number Unix 时间戳,10 位,整型数 | |||
| * nonce string 随机数 | |||
| @@ -75,60 +85,119 @@ public class TtPayController extends BaseController { | |||
| */ | |||
| @PostMapping(value = "/orderPay") | |||
| @ResponseBody | |||
| public Map<String,Object> createOrder( @RequestBody Map<String, Object> parameterMap){ | |||
| public Map<String,Object> createOrder( @RequestBody Map<String, Object> parameterMap,HttpServletRequest request){ | |||
| logger.debug("[" + getIpAddr() + "] TtOrderCallbackController::orderPay"); | |||
| Map<String,Object> resultMap = new HashMap<>(); | |||
| // String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); | |||
| logger.info("抖音支付通知-----body{}"+parameterMap); | |||
| // Map<String, Object> parameterMap = JSONObject.parseObject(body, Map.class); | |||
| logger.info("抖音通知-----body{}"+parameterMap); | |||
| try { | |||
| // Map<String, Object> parameterMap = JSONObject.parseObject(body, Map.class); | |||
| String timestamp = (String) parameterMap.get("timestamp"); | |||
| String nonce = (String) parameterMap.get("nonce"); | |||
| // {"appid":"tt9da4eb19029c2bb301","cp_orderno":"557490321114062848","cp_extra":"","way":"2","channel_no":"2021052622001418391405536769","channel_gateway_no":"12105260162116189897","payment_order_no":"2021052622001418391405536769","out_channel_order_no":"","total_amount":100} | |||
| String msg = (String) parameterMap.get("msg"); | |||
| String type = (String) parameterMap.get("type"); | |||
| String msgSignature = (String) parameterMap.get("msg_signature"); | |||
| String version = (String) parameterMap.get("version"); | |||
| Map<String, Object> pMap = JSONObject.parseObject(msg, Map.class); | |||
| String appid = (String) pMap.get("appid"); | |||
| WxAppinfo appinfo = appinfoService.getByAppId(appid); | |||
| WxPayAccount payAccount = payAccountService.getById(appinfo.getPayId()); | |||
| Map<String,Object> paramMap = new HashMap<>(); | |||
| paramMap.put("token",payAccount.getNotifyToken()); | |||
| paramMap.put("timestamp",timestamp); | |||
| paramMap.put("nonce",nonce); | |||
| paramMap.put("msg",msg); | |||
| String sign = DouYinPayHelper.getTTBackSign(paramMap, "SHA1"); | |||
| if(!msgSignature.equalsIgnoreCase(sign)){ | |||
| resultMap.put("err_tips","error"); | |||
| return resultMap; | |||
| String appid; | |||
| WxAppinfo appinfo; | |||
| WxPayAccount payAccount; | |||
| Boolean is2_0 = false; | |||
| if(StringUtils.isNotBlank(version) && "2.0".equals(version)){//支付2.0 回调 | |||
| is2_0 = true; | |||
| String msgSignature = request.getHeader("Byte-Signature"); | |||
| String timestamp = request.getHeader("Byte-Timestamp"); | |||
| String nonce = request.getHeader("Byte-Nonce-Str"); | |||
| appid = (String) pMap.get("app_id"); | |||
| appinfo = appinfoService.getByAppId(appid); | |||
| payAccount = payAccountService.getById(appinfo.getPayId()); | |||
| TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); | |||
| String beforeSign = String.format("%s\n%s\n%s\n", | |||
| timestamp, | |||
| nonce, | |||
| JSON.toJSONString(parameterMap)); | |||
| boolean verify = ttPayService.getConfig().getVerifier().verify(beforeSign.getBytes(StandardCharsets.UTF_8), msgSignature); | |||
| if(!verify){ | |||
| logger.info("抖音通知(2.0)-----{}签名效验失败"); | |||
| resultMap.put("err_tips","error"); | |||
| return resultMap; | |||
| } | |||
| logger.info("抖音通知(2.0)-----{}签名效验成功"); | |||
| }else{ | |||
| String msgSignature = (String) parameterMap.get("msg_signature"); | |||
| String timestamp = (String) parameterMap.get("timestamp"); | |||
| String nonce = (String) parameterMap.get("nonce"); | |||
| appid = (String) pMap.get("appid"); | |||
| appinfo = appinfoService.getByAppId(appid); | |||
| payAccount = payAccountService.getById(appinfo.getPayId()); | |||
| Map<String,Object> paramMap = new HashMap<>(); | |||
| paramMap.put("token",payAccount.getNotifyToken()); | |||
| paramMap.put("timestamp",timestamp); | |||
| paramMap.put("nonce",nonce); | |||
| paramMap.put("msg",msg); | |||
| String sign = DouYinPayHelper.getTTBackSign(paramMap, "SHA1"); | |||
| if(!msgSignature.equalsIgnoreCase(sign)){ | |||
| logger.info("抖音通知-----{}签名效验失败"); | |||
| resultMap.put("err_tips","error"); | |||
| return resultMap; | |||
| } | |||
| logger.info("抖音通知-----{}签名效验成功"); | |||
| } | |||
| if("payment".equals(type)){//支付回调 | |||
| String cp_orderno = (String) pMap.get("cp_orderno");//开发者传入订单号 | |||
| String out_order_no; | |||
| if(is2_0){ | |||
| out_order_no = (String)pMap.get("out_order_no"); | |||
| }else{ | |||
| out_order_no = (String) pMap.get("cp_orderno"); | |||
| } | |||
| String way = (String) pMap.get("way");//2-支付宝,1-微信 | |||
| if (!StringUtils.isNotBlank(cp_orderno)) { | |||
| if (!StringUtils.isNotBlank(out_order_no)) { | |||
| try { | |||
| Long payOrderId = Long.valueOf(cp_orderno); | |||
| WxPayOrder wxpayOrder = wxPayOrderService.getById(payOrderId, appinfo.getTenantId()); | |||
| Long orderId = Long.valueOf(out_order_no); | |||
| WxPayOrder wxpayOrder = wxPayOrderService.getById(orderId, appinfo.getTenantId()); | |||
| if(wxpayOrder == null){ | |||
| TenantEntity tenantEntity = new TenantEntity(); | |||
| tenantEntity.setTenantId(appinfo.getTenantId()); | |||
| tenantEntity.setParentTenantId(appinfo.getParentTenantId()); | |||
| WxBatchOrder batchOrder = wxOrderService.getWxBatchOrder(tenantEntity,orderId); | |||
| if(batchOrder == null){ | |||
| logger.error("未找到订单"+orderId); | |||
| } | |||
| } | |||
| PayQueryAdapterResult queryResult = payServiceFactory.getPayAdapterService(wxpayOrder.getPayVendor()).queryPayStatus(wxpayOrder, appinfo, payAccount); | |||
| if (EnumPayStatus.PAY_STATUS_SUCCESS.getCode() == queryResult.getCode()) { | |||
| WxComposeOrder composeOrder = orderFactory.getOrderAdapterService(wxpayOrder.getComposeOrder()).getComposeOrder(wxpayOrder.getOrderId(), wxpayOrder.getTenantId()); | |||
| wxPayOrderService.handleSuccessOrder(wxpayOrder, composeOrder, queryResult, true,false); | |||
| } | |||
| } catch (NumberFormatException e) { | |||
| logger.error("payOrderId参数不正确: " + paramMap.toString() + ", e:" + e.getMessage()); | |||
| logger.error("payOrderId参数不正确: " + toString() + ", e:" + e.getMessage()); | |||
| } | |||
| } | |||
| resultMap.put("err_no",0); | |||
| resultMap.put("err_tips","success"); | |||
| }else if("refund".equals(type)){//退款回调 | |||
| String cp_refundno = (String) pMap.get("cp_refundno"); | |||
| String status = (String) pMap.get("status"); | |||
| Integer refund_amount = (Integer) pMap.get("refund_amount"); | |||
| String cp_refundno,status; | |||
| Integer refund_amount; | |||
| if(is2_0){ | |||
| cp_refundno = (String) pMap.get("out_refund_no"); | |||
| status = (String) pMap.get("status"); | |||
| refund_amount = (Integer) pMap.get("refund_total_amount"); | |||
| }else{ | |||
| cp_refundno = (String) pMap.get("cp_refundno"); | |||
| status = (String) pMap.get("status"); | |||
| refund_amount = (Integer) pMap.get("refund_amount"); | |||
| } | |||
| Map<String,String> map = new HashMap<>(); | |||
| map.put("appid",appid); | |||
| @@ -150,6 +219,8 @@ public class TtPayController extends BaseController { | |||
| resultMap.put("err_no",0); | |||
| resultMap.put("err_tips","success"); | |||
| }else if("settle".equals(type)){ | |||
| } | |||
| return resultMap; | |||
| @@ -0,0 +1,123 @@ | |||
| package com.iformall.controller.callback; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.iformall.controller.base.BaseController; | |||
| import com.iformall.domain.po.TtCouponChannelPoi; | |||
| import com.iformall.domain.po.WxAppinfo; | |||
| import com.iformall.enums.EnumSpuSyncStatus; | |||
| import com.iformall.service.*; | |||
| import com.iformall.utils.DateUtils; | |||
| import me.chanjar.weixin.common.util.crypto.SHA1; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import java.util.Date; | |||
| 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()); | |||
| @Autowired | |||
| private String fmExceptionEmails; | |||
| @Autowired | |||
| private MailService mailService; | |||
| @Autowired | |||
| private WxAppinfoService wxAppinfoService; | |||
| @Autowired | |||
| private TtCouponGoodsService ttCouponGoodsService; | |||
| /** | |||
| * { | |||
| * "event": "verify_webhook", | |||
| * "client_key": "", | |||
| * "content": { | |||
| * "challenge": 12345 | |||
| * } | |||
| * } | |||
| */ | |||
| @PostMapping(value = "/notice") | |||
| @ResponseBody | |||
| public Map<String,Object> notice( @RequestBody Map<String, Object> parameterMap,HttpServletRequest request){ | |||
| logger.debug("[" + getIpAddr() + "] TtOrderCallbackController::notice"); | |||
| logger.info("抖音开放平台通知-----{}"+JSON.toJSONString(parameterMap)); | |||
| Map<String,Object> resultMap = new HashMap<>(); | |||
| String event = (String) parameterMap.get("event"); | |||
| String client_key = (String) parameterMap.get("client_key"); | |||
| WxAppinfo appInfo = wxAppinfoService.getByAppId(client_key); | |||
| if(appInfo == null){ | |||
| resultMap.put("err_code",1000); | |||
| resultMap.put("err_tips","error"); | |||
| return resultMap; | |||
| } | |||
| String header = request.getHeader("X-Douyin-Signature"); | |||
| String sha1gen = SHA1.gen(appInfo.getSecret(), JSON.toJSONString(parameterMap)); | |||
| //发邮件 | |||
| String[] receivers = fmExceptionEmails.split(","); | |||
| StringBuilder sb = new StringBuilder(); | |||
| sb.append(DateUtils.date2String(new Date())); | |||
| sb.append("\n"); | |||
| sb.append("抖音开放平台通知{}"+JSON.toJSONString(parameterMap)); | |||
| sb.append("\n"); | |||
| sb.append("sha1gen{}"+sha1gen); | |||
| sb.append("\n"); | |||
| sb.append("header{}"+header); | |||
| //发送邮件 | |||
| mailService.sendSimpleMail(receivers, "抖音开放平台通知", sb.toString()); | |||
| String content = (String) parameterMap.get("content"); | |||
| JSONObject jsonObject = JSON.parseObject(content); | |||
| if("verify_webhook".equals(event)){ | |||
| String challenge = jsonObject.getString("challenge"); | |||
| // String challenge = (String) content.get("challenge"); | |||
| resultMap.put("challenge",challenge); | |||
| return resultMap; | |||
| }else if("life_goods_audit".equals(event)){ | |||
| String product_id = jsonObject.getString("product_id"); | |||
| String reason = jsonObject.getString("reason"); | |||
| String status = jsonObject.getString("status"); | |||
| // String product_id = content.get("product_id").toString(); | |||
| // String reason = (String) content.get("reason"); | |||
| // String status = (String) content.get("status"); | |||
| TtCouponChannelPoi couponChannelPoi = new TtCouponChannelPoi(); | |||
| couponChannelPoi.updateTenantInfo(appInfo); | |||
| couponChannelPoi.setSpuId(product_id); | |||
| if("FAIL".equals(status)){ | |||
| couponChannelPoi.setLastStatus(EnumSpuSyncStatus.sync_audit_rejection.getCode()); | |||
| couponChannelPoi.setLastStatusDesc(reason); | |||
| }else if("PASS".equals(status)){ | |||
| couponChannelPoi.setLastStatus(EnumSpuSyncStatus.sync_audit_pass.getCode()); | |||
| couponChannelPoi.setLastStatusDesc(reason); | |||
| }else{ | |||
| resultMap.put("err_code",1000); | |||
| resultMap.put("err_tips","error"); | |||
| return resultMap; | |||
| } | |||
| ttCouponGoodsService.handlerTtGoodsAudit(couponChannelPoi); | |||
| resultMap.put("err_code",0); | |||
| resultMap.put("err_tips","success"); | |||
| return resultMap; | |||
| } | |||
| resultMap.put("err_code",1000); | |||
| resultMap.put("err_tips","error"); | |||
| return resultMap; | |||
| } | |||
| } | |||
| @@ -39,6 +39,8 @@ public class MqBaseConsumer { | |||
| @Autowired | |||
| private FmInsideOrderPushMsgServiceImpl fmInsideOrderPushMsgService; | |||
| @Autowired | |||
| private FmInsideOrderPushDeliveryMsgServiceImpl fmInsideOrderPushDeliveryMsgServiceImpl; | |||
| @Autowired | |||
| private FmInsideCLoginMsgServiceImpl fmInsideCLoginMsgService; | |||
| @Autowired | |||
| private MqBaseProducer mqBaseProducer; | |||
| @@ -115,6 +117,11 @@ public class MqBaseConsumer { | |||
| FmInsideOrderPushMsg msg = (FmInsideOrderPushMsg)JsonUtil.readValue(message,FmInsideOrderPushMsg.class); | |||
| fmInsideOrderPushMsgService.send(msg); | |||
| } | |||
| else if(EnumMsgRecordType.INSIDE_ORDER_PUSH_DELIVERY.getCode().equals(baseMsg.getMsgType())) { | |||
| // 内部消息 - 2.0核销同步 | |||
| FmInsideOrderPushMsg msg = (FmInsideOrderPushMsg)JsonUtil.readValue(message,FmInsideOrderPushMsg.class); | |||
| fmInsideOrderPushDeliveryMsgServiceImpl.send(msg); | |||
| } | |||
| //else if(EnumMsgRecordType.INSIDE_NOTIFY_PAY_SUCCESS.getCode().equals(baseMsg.getMsgType())) { | |||
| // 内部消息 - 微信支付通知 | |||
| //FmInsideNotifyPaySuccessMsg msg = (FmInsideNotifyPaySuccessMsg)JsonUtil.readValue(message,FmInsideNotifyPaySuccessMsg.class); | |||
| @@ -68,13 +68,13 @@ public class CouponExpiringSchedule { | |||
| wxCouponSendMapper.offExpiriedCouponSendByCouponStatus(mall.getTenantId()); | |||
| List<Long> ids = wxCouponChannelMapper.getExpiriedCouponChannelIdsByCouponStatus(mall.getTenantId()); | |||
| List<Long> couponIds = wxCouponChannelMapper.getExpiriedCouponIdsByCouponStatus(mall.getTenantId()); | |||
| wxCouponChannelMapper.offExpiriedCouponChannelByCouponStatus(mall.getTenantId()); | |||
| //同步poi | |||
| if(ids != null && ids.size() > 0){ | |||
| for (Long id: ids) { | |||
| if(couponIds != null && couponIds.size() > 0){ | |||
| for (Long couponId: couponIds) { | |||
| try{ | |||
| wxCouponChannelService.spuStatusSync(mall,id); | |||
| wxCouponChannelService.spuStatusSyncByCoupon(mall,couponId); | |||
| }catch(Exception e){ | |||
| logger.error("send spuStatusSync error: " + e.getMessage()); | |||
| } | |||
| @@ -107,34 +107,34 @@ public class CouponExpiringSchedule { | |||
| List<WxMall> malls = getMalls(); | |||
| for (WxMall mall : malls) { | |||
| try { | |||
| List<Long> ids = new ArrayList<>(); | |||
| List<Long> couponIds = new ArrayList<>(); | |||
| List<Long> id1s = wxCouponChannelMapper.getExpiriedCouponChannelIdsByEndTime(mall.getTenantId()); | |||
| if(id1s != null && id1s.size() > 0){ | |||
| ids.removeAll(id1s); | |||
| ids.addAll(id1s); | |||
| List<Long> couponId1s = wxCouponChannelMapper.getExpiriedCouponIdsByEndTime(mall.getTenantId()); | |||
| if(couponId1s != null && couponId1s.size() > 0){ | |||
| couponIds.removeAll(couponId1s); | |||
| couponIds.addAll(couponId1s); | |||
| } | |||
| wxCouponChannelMapper.offExpiriedCouponChannelByEndTime(mall.getTenantId()); | |||
| List<Long> id2s = wxCouponChannelMapper.getExpiriedCouponChannelIdsByValidDate(mall.getTenantId()); | |||
| if(id2s != null && id2s.size() > 0){ | |||
| ids.removeAll(id2s); | |||
| ids.addAll(id2s); | |||
| List<Long> couponId2s = wxCouponChannelMapper.getExpiriedCouponIdsByValidDate(mall.getTenantId()); | |||
| if(couponId2s != null && couponId2s.size() > 0){ | |||
| couponIds.removeAll(couponId2s); | |||
| couponIds.addAll(couponId2s); | |||
| } | |||
| wxCouponChannelMapper.offExpiriedCouponChannelByValidDate(mall.getTenantId()); | |||
| List<Long> id3s = wxCouponChannelMapper.getExpiriedCouponChannelIdsByCouponStatus(mall.getTenantId()); | |||
| List<Long> id3s = wxCouponChannelMapper.getExpiriedCouponIdsByCouponStatus(mall.getTenantId()); | |||
| if(id3s != null && id3s.size() > 0){ | |||
| ids.removeAll(id3s); | |||
| ids.addAll(id3s); | |||
| couponIds.removeAll(id3s); | |||
| couponIds.addAll(id3s); | |||
| } | |||
| wxCouponChannelMapper.offExpiriedCouponChannelByCouponStatus(mall.getTenantId()); | |||
| //同步poi | |||
| if(ids != null && ids.size() > 0){ | |||
| for (Long id: ids) { | |||
| if(couponIds != null && couponIds.size() > 0){ | |||
| for (Long couponId: couponIds) { | |||
| try{ | |||
| wxCouponChannelService.spuStatusSync(mall,id); | |||
| wxCouponChannelService.spuStatusSyncByCoupon(mall,couponId); | |||
| }catch(Exception e){ | |||
| logger.error("send spuStatusSync error: " + e.getMessage()); | |||
| } | |||
| @@ -353,7 +353,7 @@ public class OrderExpiringSchedule { | |||
| wxOrderMapper.updateById(updateOrder); | |||
| logger.info("券订单: " + order.getId() + " create at " + order.getCreateDate() + " expired at " + new Date()); | |||
| wxOrderService.sendInsideOrderPushMsg(order,order.getComposeOrderId()); | |||
| // wxOrderService.sendInsideOrderPushMsg(order,order.getComposeOrderId()); | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| package com.iformall.schedule; | |||
| import com.iformall.domain.po.*; | |||
| import com.iformall.douyin.pay.TtPayService; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import com.iformall.douyin.payv2.request.TtRefundAuditMsgRequest; | |||
| import com.iformall.enums.*; | |||
| import com.iformall.mapper.*; | |||
| import com.iformall.utils.MaUtil; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.scheduling.annotation.Scheduled; | |||
| import org.springframework.stereotype.Component; | |||
| import java.util.List; | |||
| @Component | |||
| public class OrderRefundAuditSchedule { | |||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
| @Autowired | |||
| WxOrderMapper wxOrderMapper; | |||
| @Autowired | |||
| WxAppinfoMapper wxAppinfoMapper; | |||
| @Autowired | |||
| WxRefundOrderMapper wxRefundOrderMapper; | |||
| @Autowired | |||
| WxPayAccountMapper wxPayAccountMapper; | |||
| @Autowired | |||
| MaUtil maUtil; | |||
| private List<WxAppinfo> getAppInfos() { | |||
| WxAppinfo appinfo =new WxAppinfo(); | |||
| appinfo.setPlat(EnumAppPlat.TOUTIAO.getCode()); | |||
| appinfo.setType(EnumAppType.C.getCode()); | |||
| return wxAppinfoMapper.findList(appinfo); | |||
| } | |||
| @Scheduled(cron = "0 */10 * * * *?") // 每10分钟检查一次 | |||
| //@Scheduled(cron = "*/10 * * * * ?") // 测试10秒中一次 | |||
| public void merchantAuditCallback() { | |||
| logger.info("退款自动审核start"); | |||
| List<WxAppinfo> appInfos = getAppInfos(); | |||
| for (WxAppinfo appinfo : appInfos) { | |||
| WxRefundOrder refundOrder = new WxRefundOrder(); | |||
| refundOrder.updateTenantInfo(appinfo); | |||
| refundOrder.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); | |||
| List<WxRefundOrder> list = wxRefundOrderMapper.findList(refundOrder); | |||
| if(list != null && list.size() > 0){ | |||
| WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); | |||
| TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); | |||
| for (WxRefundOrder order:list) { | |||
| try { | |||
| TtRefundAuditMsgRequest request = new TtRefundAuditMsgRequest(); | |||
| request.setOutRefundNo(order.getId().toString()); | |||
| request.setRefundAuditStatus(1); | |||
| ttPayService.merchantAuditCallback(request); | |||
| } catch (TtPayException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -42,8 +42,8 @@ public class SharingOrderRedoSchedule { | |||
| } | |||
| @Async | |||
| @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨02:00分账重试 | |||
| // @Scheduled(cron = "0 0 0/1 * * ?") // 测试 | |||
| // @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨02:00分账重试 | |||
| @Scheduled(cron = "0 0/10 * * * ?") // 测试 | |||
| public void sharingOrderResultSchedule() { | |||
| List<WxMall> malls = getMalls(); | |||
| for (WxMall mall: malls) { | |||
| @@ -35,8 +35,8 @@ public class SharingOrderResultSchedule { | |||
| } | |||
| @Async | |||
| @Scheduled(cron = "0 15 0 * * ?") // 每天凌晨3:00更新分账结果 | |||
| //@Scheduled(cron = "*/10 * * * * ?") // 测试10秒中一次 | |||
| // @Scheduled(cron = "0 15 0 * * ?") // 每天凌晨3:00更新分账结果 | |||
| @Scheduled(cron = "* */15 * * * ?") // 测试10秒中一次 | |||
| public void sharingOrderResultSchedule() { | |||
| List<WxMall> malls = getMalls(); | |||
| for (WxMall mall: malls) { | |||
| @@ -59,21 +59,21 @@ public class TtMerchantPoiSchedule { | |||
| // } | |||
| // } | |||
| @Async | |||
| @Scheduled(cron = "0 0 */1 * * *?") // 每小时检查一次 | |||
| public void supplierQueryTaskSchedule() { | |||
| TtCouponChannelPoi ttCouponChannelPoi = new TtCouponChannelPoi(); | |||
| ttCouponChannelPoi.setLastStatus(EnumSpuSyncStatus.sync_auditing.getCode()); | |||
| List<TtCouponChannelPoi> list = ttCouponChannelPoiMapper.findList(ttCouponChannelPoi); | |||
| if(list != null && list.size() > 0){ | |||
| for (TtCouponChannelPoi poi:list) { | |||
| try{ | |||
| ttMerchantPoiService.spuGet(poi,poi.getId()); | |||
| }catch(Exception e){ | |||
| logger.error("查询商品同步任务失败"); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // @Async | |||
| // @Scheduled(cron = "0 0 */1 * * *?") // 每小时检查一次 | |||
| // public void supplierQueryTaskSchedule() { | |||
| // TtCouponChannelPoi ttCouponChannelPoi = new TtCouponChannelPoi(); | |||
| // ttCouponChannelPoi.setLastStatus(EnumSpuSyncStatus.sync_auditing.getCode()); | |||
| // List<TtCouponChannelPoi> list = ttCouponChannelPoiMapper.findList(ttCouponChannelPoi); | |||
| // if(list != null && list.size() > 0){ | |||
| // for (TtCouponChannelPoi poi:list) { | |||
| // try{ | |||
| // ttMerchantPoiService.spuGet(poi,poi.getId()); | |||
| // }catch(Exception e){ | |||
| // logger.error("查询商品同步任务失败"); | |||
| // } | |||
| // } | |||
| // } | |||
| // } | |||
| } | |||
| @@ -24,13 +24,13 @@ public class TtOrderPushErrorSchedule { | |||
| private WxOrderService wxOrderService; | |||
| @Async | |||
| @Scheduled(cron = "0 0 1 * * ?") | |||
| @Scheduled(cron = "0 0 */2 * * ?") | |||
| public void OrderPushErrorTaskSchedule() { | |||
| List<TtOrderPushError> orderPushErrors = ttOrderPushErrorMapper.findList(new TtOrderPushError()); | |||
| if(orderPushErrors != null && orderPushErrors.size() > 0){ | |||
| for (TtOrderPushError error:orderPushErrors) { | |||
| try{ | |||
| wxOrderService.sendInsideOrderPushMsg(error,error.getId()); | |||
| wxOrderService.sendInsideOrderPushDeliveryMsg(error,null,error.getId()); | |||
| }catch(Exception e){ | |||
| logger.error("订单同步重试error"); | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| package com.iformall.domain.dto; | |||
| import lombok.Data; | |||
| import java.io.Serializable; | |||
| import com.iformall.domain.po.UserBasicInfoAddress; | |||
| import com.iformall.domain.po.WxCoupon; | |||
| import com.iformall.domain.po.WxCouponChannel; | |||
| @Data | |||
| public class PlatPushOrderSaveDto implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| Long couponChannelId;//【传入参数】渠道商品编号,对饮我们系统的编号 | |||
| int count;//【传入参数】购买数量 | |||
| Long orderGroupId;//【传入参数】拼团主订单号 | |||
| boolean isPress = false;//【传入参数】,是否砍价 | |||
| String formId ; //【传入参数】,非必传 | |||
| Integer shippingType = 0;//EnumOrderShopingType【传入参数】配送类型 | |||
| UserBasicInfoAddress address;//【传入参数】配送地址 | |||
| String extParam;//数组格式长度与数量一致(一个券一个订单时)【传入参数】json,额外的信息,可能每个平台不一样 | |||
| WxCoupon wxCoupon;//【非传入参数】。 | |||
| WxCouponChannel wxCouponChannel;//【非传入参数】。 | |||
| } | |||
| @@ -17,11 +17,15 @@ import java.util.Date; | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class TtCouponChannelPoi extends TenantEntity { | |||
| protected Long id;//coupon_channel_id | |||
| protected Long id;//coupon_id | |||
| @io.swagger.annotations.ApiModelProperty(value="couponChannelId",name="couponChannelId") | |||
| private Long couponChannelId; | |||
| @io.swagger.annotations.ApiModelProperty(value="spuId",name="spuId") | |||
| private String spuId; | |||
| //该字段状态更新不及时,不作为业务使用 | |||
| @io.swagger.annotations.ApiModelProperty(value="状态:0-审核中,1-上架,2-下架,3-审核拒绝 4-审核通过",name="status") | |||
| private Integer status; | |||
| @@ -0,0 +1,29 @@ | |||
| package com.iformall.domain.po; | |||
| import com.baomidou.mybatisplus.annotation.TableField; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.iformall.domain.po.base.BaseEntity; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| @TableName(value = "tt_goods_category") | |||
| @Data | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class TtGoodsCategory extends BaseEntity { | |||
| protected Integer id; | |||
| @io.swagger.annotations.ApiModelProperty(value="",name="name") | |||
| private String name; | |||
| @io.swagger.annotations.ApiModelProperty(value="",name="parentId") | |||
| private Integer parentId; | |||
| @TableField(exist = false) | |||
| protected List<TtGoodsCategory> child; | |||
| } | |||
| @@ -1,5 +1,8 @@ | |||
| package com.iformall.domain.po; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils; | |||
| import com.baomidou.mybatisplus.annotation.TableField; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| @@ -42,6 +45,9 @@ public class WxBatchOrder extends TenantEntity { | |||
| @io.swagger.annotations.ApiModelProperty(value = "EnumYesOrNo是否抖音poi订单", name = "isTtPoiOrder") | |||
| private Integer isTtPoiOrder; | |||
| @io.swagger.annotations.ApiModelProperty(value = "额外参数,总参数", name = "extParam") | |||
| private String extParam; | |||
| @TableField(exist = false) | |||
| @io.swagger.annotations.ApiModelProperty(value = "订单集合", name = "orders") | |||
| @@ -56,4 +62,15 @@ public class WxBatchOrder extends TenantEntity { | |||
| return null; | |||
| } | |||
| public Object getExpParamValue(String key) { | |||
| if (StringUtils.isBlank(extParam)) { | |||
| return null; | |||
| } | |||
| JSONObject o = JSON.parseObject(extParam); | |||
| if (null == o ) { | |||
| return null; | |||
| } | |||
| return o.get(key); | |||
| } | |||
| } | |||
| @@ -1,10 +1,12 @@ | |||
| package com.iformall.domain.po; | |||
| import com.aliyun.openservices.shade.com.alibaba.fastjson.JSONObject; | |||
| import com.baomidou.mybatisplus.annotation.TableField; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.iformall.common.SortColumn; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.vo.WxCouponStatisVo; | |||
| import com.iformall.douyin.web.bean.GoodsTemplateGet; | |||
| import com.iformall.enums.EnumCouponType; | |||
| import com.iformall.enums.EnumValidStatus; | |||
| import com.iformall.utils.Constant; | |||
| @@ -14,6 +16,7 @@ import cn.afterturn.easypoi.excel.annotation.Excel; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import lombok.ToString; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import java.math.BigDecimal; | |||
| @@ -237,9 +240,60 @@ public class WxCoupon extends TenantEntity { | |||
| @io.swagger.annotations.ApiModelProperty(value="富文本内容",name="html") | |||
| private String html; | |||
| //List<Long> String | |||
| @io.swagger.annotations.ApiModelProperty(value="卷包内容",name="giftList") | |||
| private String giftList; | |||
| @io.swagger.annotations.ApiModelProperty(value="EnumTtProductType",name="productType") | |||
| private Integer productType; | |||
| @io.swagger.annotations.ApiModelProperty(value="tt_goods_category",name="categoryId") | |||
| private Integer categoryId; | |||
| @io.swagger.annotations.ApiModelProperty(value="JSON",name="productAttrs") | |||
| private String productAttrs; | |||
| @TableField(exist = false) | |||
| private Map<String,String> productAttrKeyValueMap; | |||
| public Map<String,String> getProductAttrKeyValueMap(){ | |||
| Map<String,String> productAttrKeyValueMap = new HashMap<>(); | |||
| if(StringUtils.isNotBlank(productAttrs)){ | |||
| try{ | |||
| List<GoodsTemplateGet.ProductAttrs> productAttrs = JSONObject.parseArray(this.productAttrs, GoodsTemplateGet.ProductAttrs.class); | |||
| for (GoodsTemplateGet.ProductAttrs attr:productAttrs) { | |||
| if(StringUtils.isNotBlank(attr.getData())){ | |||
| productAttrKeyValueMap.put(attr.getKey(),attr.getData()); | |||
| } | |||
| } | |||
| }catch(Exception e){ | |||
| } | |||
| } | |||
| return productAttrKeyValueMap; | |||
| } | |||
| @io.swagger.annotations.ApiModelProperty(value="JSON",name="skuAttrs") | |||
| private String skuAttrs; | |||
| @TableField(exist = false) | |||
| private Map<String,String> skuAttrKeyValueMap; | |||
| public Map<String,String> getSkuAttrKeyValueMap(){ | |||
| Map<String,String> skuAttrKeyValueMap = new HashMap<>(); | |||
| if(StringUtils.isNotBlank(skuAttrs)){ | |||
| try{ | |||
| List<GoodsTemplateGet.ProductAttrs> skuAttrs = JSONObject.parseArray(this.skuAttrs, GoodsTemplateGet.ProductAttrs.class); | |||
| for (GoodsTemplateGet.ProductAttrs attr:skuAttrs) { | |||
| if(StringUtils.isNotBlank(attr.getData())){ | |||
| skuAttrKeyValueMap.put(attr.getKey(),attr.getData()); | |||
| } | |||
| } | |||
| }catch(Exception e){ | |||
| } | |||
| } | |||
| return skuAttrKeyValueMap; | |||
| } | |||
| @TableField(exist = false) | |||
| private List<WxCoupon> giftCouponList; | |||
| @@ -1,5 +1,8 @@ | |||
| package com.iformall.domain.po; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils; | |||
| import com.baomidou.mybatisplus.annotation.TableField; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.fasterxml.jackson.annotation.JsonFormat; | |||
| @@ -83,6 +86,21 @@ public class WxCouponOrder extends TenantEntity { | |||
| @io.swagger.annotations.ApiModelProperty(value="补贴",name="subsidy") | |||
| private Integer subsidy; | |||
| @io.swagger.annotations.ApiModelProperty(value="额外参数,用于第三方平台",name="extParam") | |||
| private String extParam; | |||
| public Object getExpParamValue(String key) { | |||
| if (StringUtils.isBlank(extParam)) { | |||
| return null; | |||
| } | |||
| JSONObject o = JSON.parseObject(extParam); | |||
| if (null == o ) { | |||
| return null; | |||
| } | |||
| return o.get(key); | |||
| } | |||
| @TableField(exist = false) | |||
| private String couponName; | |||
| @@ -346,6 +346,10 @@ public class WxMerchant extends TenantEntity { | |||
| @TableField(exist = false) | |||
| private String addr; | |||
| @io.swagger.annotations.ApiModelProperty(value=" supplierExtId",name="supplierExtId") | |||
| @TableField(exist = false) | |||
| private String supplierExtId; | |||
| @io.swagger.annotations.ApiModelProperty(value="ttPoi",name="ttPoi") | |||
| @TableField(exist = false) | |||
| private String ttPoi; | |||
| @@ -1,6 +1,10 @@ | |||
| package com.iformall.domain.po; | |||
| import cn.afterturn.easypoi.excel.annotation.Excel; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils; | |||
| import com.baomidou.mybatisplus.annotation.TableField; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.iformall.common.SortColumn; | |||
| @@ -119,6 +123,19 @@ public class WxOrder extends TenantEntity { | |||
| @io.swagger.annotations.ApiModelProperty(value="父订单编号",name="parentOrderId") | |||
| private Long parentOrderId; | |||
| @io.swagger.annotations.ApiModelProperty(value="额外参数,用于第三方平台",name="extParam") | |||
| private String extParam; | |||
| public Object getExpParamValue(String key) { | |||
| if (StringUtils.isBlank(extParam)) { | |||
| return null; | |||
| } | |||
| JSONObject o = JSON.parseObject(extParam); | |||
| if (null == o ) { | |||
| return null; | |||
| } | |||
| return o.get(key); | |||
| } | |||
| @TableField(exist = false) | |||
| protected List<Long> couponIds; | |||
| @@ -12,4 +12,7 @@ public class FmInsideOrderPushMsg extends BaseMsg{ | |||
| @io.swagger.annotations.ApiModelProperty(value = "", name = "composeOrderId") | |||
| private Long batchOrderId; | |||
| @io.swagger.annotations.ApiModelProperty(value = "", name = "couponOrderId") | |||
| private Long couponOrderId; | |||
| } | |||
| @@ -10,8 +10,8 @@ import lombok.ToString; | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class FmInsideProductPushMsg extends BaseMsg{ | |||
| @io.swagger.annotations.ApiModelProperty(value = "卷Id", name = "couponChannelId") | |||
| private Long couponChannelId; | |||
| @io.swagger.annotations.ApiModelProperty(value = "卷Id", name = "couponId") | |||
| private Long couponId; | |||
| @io.swagger.annotations.ApiModelProperty(value = "同步类型", name = "syncType") | |||
| private EnumPushType syncType; | |||
| @@ -0,0 +1,41 @@ | |||
| package com.iformall.domain.vo; | |||
| import com.baomidou.mybatisplus.annotation.TableField; | |||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |||
| import com.iformall.domain.po.WxCoupon; | |||
| import com.iformall.domain.po.WxCouponChannel; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import lombok.ToString; | |||
| import java.io.Serializable; | |||
| import java.math.BigDecimal; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| /** | |||
| * Created by syf on 2018/8/22. | |||
| */ | |||
| @JsonIgnoreProperties(value = {"handler"}) | |||
| @Data | |||
| @ToString(callSuper = true) | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class TtCouponChannelVo extends WxCouponChannelVo implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @io.swagger.annotations.ApiModelProperty(value="spuId",name="spuId") | |||
| private String spuId; | |||
| @io.swagger.annotations.ApiModelProperty(value="状态:0-审核中,1-上架,2-下架,3-审核拒绝 4-审核通过",name="poiStatus") | |||
| private Integer poiStatus; | |||
| @io.swagger.annotations.ApiModelProperty(value="描述",name="statusDesc") | |||
| private String statusDesc; | |||
| @io.swagger.annotations.ApiModelProperty(value="状态:0-审核中,1-上架,2-下架,3-审核拒绝 4-审核通过",name="lastStatus") | |||
| private Integer lastStatus; | |||
| @io.swagger.annotations.ApiModelProperty(value="描述",name="lastStatusDesc") | |||
| private String lastStatusDesc; | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| package com.iformall.domain.vo; | |||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |||
| import com.iformall.domain.po.WxCoupon; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import lombok.ToString; | |||
| import java.io.Serializable; | |||
| @Data | |||
| @ToString(callSuper = true) | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class TtCouponVo extends WxCoupon implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @io.swagger.annotations.ApiModelProperty(value="couponChannelId",name="couponChannelId") | |||
| private Long couponChannelId; | |||
| @io.swagger.annotations.ApiModelProperty(value="spuId",name="spuId") | |||
| private String spuId; | |||
| @io.swagger.annotations.ApiModelProperty(value="状态:0-审核中,1-上架,2-下架,3-审核拒绝 4-审核通过",name="poiStatus") | |||
| private Integer poiStatus; | |||
| @io.swagger.annotations.ApiModelProperty(value="描述",name="statusDesc") | |||
| private String statusDesc; | |||
| @io.swagger.annotations.ApiModelProperty(value="状态:0-审核中,1-上架,2-下架,3-审核拒绝 4-审核通过",name="lastStatus") | |||
| private Integer lastStatus; | |||
| @io.swagger.annotations.ApiModelProperty(value="描述",name="lastStatusDesc") | |||
| private String lastStatusDesc; | |||
| } | |||
| @@ -220,6 +220,8 @@ public class WxCouponOrderBVo extends WxCouponOrder { | |||
| @Excel(name = "核销商户", width = 50, orderNum = "4") | |||
| @TableField(exist = false) | |||
| private String verifyMerchantName; | |||
| @TableField(exist = false) | |||
| private Long verifyMerchantId; | |||
| @TableField(exist = false) | |||
| private Long floor; | |||
| @@ -101,6 +101,10 @@ public class WxMerchantVo extends TenantEntity { | |||
| @io.swagger.annotations.ApiModelProperty(value = "置顶时间", name = "topTime") | |||
| private Date topTime; | |||
| @io.swagger.annotations.ApiModelProperty(value=" supplierExtId",name="supplierExtId") | |||
| @TableField(exist = false) | |||
| private String supplierExtId; | |||
| @io.swagger.annotations.ApiModelProperty(value="ttPoi",name="ttPoi") | |||
| @TableField(exist = false) | |||
| private String ttPoi; | |||
| @@ -132,6 +136,7 @@ public class WxMerchantVo extends TenantEntity { | |||
| this.linkLinePhone = m.getLinkLinePhone(); | |||
| this.topTime = m.getTopTime(); | |||
| this.addr = m.getAddr(); | |||
| this.supplierExtId = m.getSupplierExtId(); | |||
| this.ttPoi = m.getTtPoi(); | |||
| this.longitude = m.getLongitude(); | |||
| this.latitude = m.getLatitude(); | |||
| @@ -6,7 +6,6 @@ import java.security.NoSuchAlgorithmException; | |||
| import java.util.*; | |||
| import com.iformall.common.ErrorCode; | |||
| import com.iformall.douyin.pay.enums.AppAddSubMerchantUrlType; | |||
| import com.iformall.douyin.pay.orderQuery.QueryMerchantResult; | |||
| import com.iformall.douyin.pay.orderQuery.QueryRefundResult; | |||
| import com.iformall.douyin.pay.orderQuery.QuerySettleResult; | |||
| @@ -22,7 +21,6 @@ import com.iformall.utils.HttpUtil; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import springfox.documentation.spring.web.json.Json; | |||
| /** | |||
| * 抖音小程序支付 | |||
| @@ -356,48 +354,52 @@ public class DouYinPayHelper { | |||
| public static void main(String[] args) { | |||
| //测试 | |||
| // String mcuid = "70777649963225930610";//商户号 | |||
| String appid = "ttef6599d8705b49b101"; | |||
| String salt = "G8DdHfRcEPXB8kHQsnpVWvhLfMC7MZQ72aweTei8";//支付密钥 | |||
| // String appid = "ttef6599d8705b49b101"; | |||
| // String salt = "G8DdHfRcEPXB8kHQsnpVWvhLfMC7MZQ72aweTei8";//支付密钥 | |||
| //生产 | |||
| // String mcuid = "69739487619282066230"; | |||
| // String appid = "tt8183f73e1ebb053701"; | |||
| // String salt = "rtQwyvhZHMuMYrY6GBm8DnhvEu0fuJUVHYS2KP6P"; | |||
| String appid = "ttc0cdb6705ff345f301"; | |||
| String salt = "FhGHClzfdDEPW6Cq4hw2GyoynJbpeq6wLQyM5iub"; | |||
| AppAddSubMerchant appAddSubMerchant = new AppAddSubMerchant(); | |||
| appAddSubMerchant.setAppId("ttef6599d8705b49b101"); | |||
| appAddSubMerchant.setSalt("G8DdHfRcEPXB8kHQsnpVWvhLfMC7MZQ72aweTei8"); | |||
| appAddSubMerchant.setSubMerchantId("666438479039619072"); | |||
| appAddSubMerchant.setUrlType(2); | |||
| AppAddSubMerchantResult appAddSubMerchantResult = appAddSubMerchant(appAddSubMerchant); | |||
| System.out.println(appAddSubMerchantResult.toString()); | |||
| // AppAddSubMerchant appAddSubMerchant = new AppAddSubMerchant(); | |||
| // appAddSubMerchant.setAppId("ttef6599d8705b49b101"); | |||
| // appAddSubMerchant.setSalt("G8DdHfRcEPXB8kHQsnpVWvhLfMC7MZQ72aweTei8"); | |||
| // appAddSubMerchant.setSubMerchantId("666438479039619072"); | |||
| // appAddSubMerchant.setUrlType(2); | |||
| // AppAddSubMerchantResult appAddSubMerchantResult = appAddSubMerchant(appAddSubMerchant); | |||
| // System.out.println(appAddSubMerchantResult.toString()); | |||
| // Settle settle = new Settle(); | |||
| // settle.setAppId(appid); | |||
| // settle.setSalt(salt); | |||
| ///** | |||
| // * {"settle_params":"[{\"amount\":19,\"merchant_uid\":\"69798058370993871733\"}]", | |||
| // * "settle_desc":"客户提现。", | |||
| // * "sign":"94fa5f559880870f2fda53c67b236a3f", | |||
| // * "out_settle_no":"572578660822212608", | |||
| // * "out_order_no":"572308600038809600", | |||
| // * "app_id":"tt9da4eb19029c2bb301"} | |||
| // * {settle_params=[{"amount":6859,"merchant_uid":"70878359464980830803"}], | |||
| // * settle_desc=自主完结分账, sign=9acc782f9196bb45823fdbe7e14b24df, | |||
| // * out_settle_no=687210710707761152, | |||
| // * out_order_no=687209074036342784, app_id=ttc0cdb6705ff345f301} | |||
| // * response:{"err_no":6006,"err_tips":"其他分账方分账比例超限","settle_no":""} | |||
| // * | |||
| // * request:{settle_params=[{"amount":6900,"merchant_uid":"70878359464980830803"}], | |||
| // * settle_desc=自主完结分账, sign=d3541104ea0a6234f96ea753aa514f7c, | |||
| // * out_settle_no=687210746524631040, out_order_no=687208992638238720, app_id=ttc0cdb6705ff345f301} | |||
| // * response:{"err_no":6006,"err_tips":"其他分账方分账比例超限","settle_no":""} | |||
| // */ | |||
| // settle.setOutSettleNo("57257866081118888"); | |||
| // settle.setOutOrderNo("613967802405908480"); | |||
| // settle.setOutSettleNo("687210746524631040"); | |||
| // settle.setOutOrderNo("687208992638238720"); | |||
| // settle.setSettleDesc("手动处理。"); | |||
| // List list = new ArrayList<>(); | |||
| // Map<String,Object> settleParams = new HashMap<>(); | |||
| // settleParams.put("merchant_uid",mcuid); | |||
| // settleParams.put("amount",5); | |||
| // settleParams.put("merchant_uid","70878359464980830803"); | |||
| // settleParams.put("amount",6859); | |||
| // list.add(settleParams); | |||
| // settle.setSettleParams(JSON.toJSONString(list)); | |||
| // SettleResult settle1 = settle(settle); | |||
| // System.out.println(settle1.toString()); | |||
| // QuerySettleResult querySettleResult = settleQuery(appid, salt, "57257866081118888", null); | |||
| // System.out.println(querySettleResult.toString()); | |||
| QuerySettleResult querySettleResult = settleQuery(appid, salt, "687210746524631040", null); | |||
| System.out.println(querySettleResult.toString()); | |||
| // OrderQueryResult orderQueryResult = orderQuery(appid, salt, "613879951804915712", null); | |||
| // System.out.println(orderQueryResult.toString()); | |||
| @@ -0,0 +1,48 @@ | |||
| package com.iformall.douyin.pay; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import com.iformall.douyin.payv2.request.ProfitSharingRequest; | |||
| import com.iformall.douyin.payv2.result.ProfitSharingResult; | |||
| /** | |||
| * 支付V2-资金应用-分账 | |||
| * https://bytedance.feishu.cn/docx/doxcnj21j74jHyXEq6Ybg3AzOxh | |||
| * @author pg 2021-6-23 | |||
| * @date 2021-6-23 | |||
| */ | |||
| public interface ProfitSharingV2Service { | |||
| /** | |||
| * <pre> | |||
| * 请求分账API | |||
| * 接口简介 | |||
| * 一笔订单完成后,开发者可以通过分账接口将这笔订单产生的资金结算给各个分账方。 | |||
| * - 结算规则统一为核销D+3; | |||
| * - CPS订单比较特殊,统一结算规则是核销D+3 | |||
| * - 结算规则为核销D+3,表示订单到达“终态”3天后可以分账,“终态”表示所有的券/商品已核销或已退款 | |||
| * - 如对上述结算规则有特殊需求,请联系对应行业经理(餐饮@Xinru Chen 酒旅@Jie Zhou @Yuekai Zhao 到综@Yankai Ouyang ) | |||
| * - 若分账失败,请参考文档进行自查分账失败如何自查 | |||
| * 核销D+3 | |||
| * - 例如用户的一笔订单买了5张团购券,其中3张先核销,剩余2张再退款,最终退款完成的时间就是订单到达终态的时间。订单到达终态3天后,则可以发起分账 | |||
| * | |||
| * 返回 小程序分账id,系统会确保不超过64个字节(数字+ASCII) | |||
| * | |||
| */ | |||
| String profitSharing(ProfitSharingRequest request) throws TtPayException; | |||
| /** | |||
| * <pre> | |||
| * 查询分账接口 | |||
| * out_order_no string 否 开发者交易订单id,长度<64byte,数字ASCII字符 | |||
| * out_settle_no string 否 开发者分账单id,长度<64byte,数字、ASCII字符 | |||
| * order_id string 否 抖音开平侧订单id,长度<64byte,数字、ASCII | |||
| * settle_id string 否 抖音开平侧分账单id,长度<64byte,数字、ASCII | |||
| * - 查询优先级: settle_id > order_id > out_settle_no > out_order_no,4个参数选填一个 | |||
| * - 例如:请求填写了settle_id和order_id,服务只会按settle_id来查询,忽略order_id | |||
| * - 如果未查询到结果,会返回空数组 | |||
| * - 注意:对于担保交易和交易1.0的订单,如果需要根据order_id/out_order_no查询订单的分账记录,建议使用order_id(抖音开平侧支付单id查询),若使用out_order_no可能存在查询不到的情况 | |||
| * | |||
| */ | |||
| ProfitSharingResult getProfitSharingResult(String out_settle_no) throws TtPayException; | |||
| } | |||
| @@ -0,0 +1,201 @@ | |||
| package com.iformall.douyin.pay; | |||
| import com.github.binarywang.wxpay.bean.WxPayApiData; | |||
| import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import com.iformall.douyin.payv2.config.TtPayConfig; | |||
| import com.iformall.douyin.payv2.request.*; | |||
| import com.iformall.douyin.payv2.result.*; | |||
| import org.apache.http.client.methods.HttpPost; | |||
| import org.apache.http.client.methods.HttpRequestBase; | |||
| /** | |||
| * <pre> | |||
| * 支付相关接口. | |||
| * Created by Binary Wang on 2016/7/28. | |||
| * </pre> | |||
| * | |||
| */ | |||
| public interface TtPayService { | |||
| /** | |||
| * 获取微信支付请求url前缀,沙箱环境可能不一样. | |||
| * | |||
| * @return the pay base url | |||
| */ | |||
| String getPayBaseUrl(); | |||
| /** | |||
| * 发送post请求,得到响应字符串. | |||
| * | |||
| * @param url 请求地址 | |||
| * @param requestStr 请求信息 | |||
| * @return 返回请求结果字符串 string | |||
| * @throws TtPayException the tt pay exception | |||
| */ | |||
| String postV2(String url, String requestStr) throws TtPayException; | |||
| /** | |||
| * 发送post请求,得到响应字符串. | |||
| * | |||
| * @param url 请求地址 | |||
| * @param httpPost 请求信息 | |||
| * @return 返回请求结果字符串 string | |||
| * @throws TtPayException the tt pay exception | |||
| */ | |||
| String postV2(String url, HttpPost httpPost) throws TtPayException; | |||
| /** | |||
| * 发送http请求,得到响应字符串. | |||
| * | |||
| * @param url 请求地址 | |||
| * @param httpRequest 请求信息,可以是put,post,get,delete等请求 | |||
| * @return 返回请求结果字符串 string | |||
| * @throws TtPayException the tt pay exception | |||
| */ | |||
| String requestV2(String url, HttpRequestBase httpRequest) throws TtPayException; | |||
| /** | |||
| * 发送get V2请求,得到响应字符串. | |||
| * | |||
| * @param url 请求地址 | |||
| * @return 返回请求结果字符串 string | |||
| * @throws TtPayException the tt pay exception | |||
| */ | |||
| String getV2(String url) throws TtPayException; | |||
| /** | |||
| * 获取分账服务类. | |||
| * | |||
| * @return the ent pay service | |||
| */ | |||
| ProfitSharingV2Service getProfitSharingV2Service(); | |||
| /** | |||
| * 2.1 交易回调设置接口 | |||
| */ | |||
| boolean callbackSettings(CallBackSettingsRequest settings) throws TtPayException; | |||
| /** | |||
| * 2.2 查询交易回调设置接口 | |||
| */ | |||
| CallBackSettingsRequest querySettings() throws TtPayException; | |||
| /** | |||
| * 解析预下单回调 | |||
| * | |||
| */ | |||
| CreateOrderCallback parseOrderNotifyV2Result(String notifyData, SignatureHeader header) throws TtPayException; | |||
| /** | |||
| * 交易系统2.0模版下单依赖入口前端js-api,如果用户没有更新抖音,就没法使用模版下单,开发者可用该接口替用户发起下单,开发者发起的下单流程则不会有预下单回调,当低版本减少后,会下掉该接口,请不要应用于其它场景,否则会影响业务(对于poi商品,目前只支持团购券) | |||
| * @param request | |||
| * @return | |||
| * @throws TtPayException | |||
| */ | |||
| TtPayUnifiedOrderV2Result createOrderV2(TtPayUnifiedOrderV2Request request) throws TtPayException; | |||
| /** | |||
| * <pre> | |||
| * 5. 订单信息接口 | |||
| */ | |||
| TtPayOrderQueryV2Result queryOrderV2(String orderId, String outOrderNo) throws TtPayException; | |||
| /** | |||
| * <pre> | |||
| * 5. 订单信息接口 | |||
| */ | |||
| TtPayOrderQueryV2Result queryOrderV2(TtPayOrderQueryV2Request request) throws TtPayException; | |||
| /** | |||
| * <pre> | |||
| * 5. cps订单信息接口 | |||
| */ | |||
| TtPayCpsOrderQueryV2Result queryCpsOrderV2(String orderId, String outOrderNo) throws TtPayException; | |||
| /** | |||
| * 推送核销状态(非闭环核销) | |||
| */ | |||
| boolean pushDelivery(TtOrderPushDeliveryRequest request) throws TtPayException; | |||
| /** | |||
| * 获取配置. | |||
| * | |||
| * @return the config | |||
| */ | |||
| TtPayConfig getConfig(); | |||
| /** | |||
| * 设置配置对象. | |||
| * | |||
| * @param config the config | |||
| */ | |||
| void setConfig(TtPayConfig config); | |||
| /** | |||
| * <pre> | |||
| * 开发者可用该接口替用户发起退款,开发者发起的退款流程则不会有退款申请回调。 | |||
| * - 过期自动退说明 | |||
| * - 过期自动退的退款被拒绝退款后,不会再次发起。 | |||
| * - 在交易系统2.0产生的订单,如果用户购买的商品是过期退商品,交易系统2.0会自动发起退款,创建退款单,退款流程和用户发起退款流程相同。 | |||
| * - 发起过期自动退条件 | |||
| * - 非POI 商品 | |||
| * - 前端传入合法的商品过期时间 | |||
| * - 前端传入的goodsLabels中包含过期退标签 | |||
| * - POI 商品 | |||
| * - POI 商品设置了过期时间 | |||
| * - POI 商品的 sub_title包含过期退标签 | |||
| * - 旧订单系统不会自动发起过期自动退,仍需开发者处理。 | |||
| * - 过期自动退的退款单由系统创建,因此 退款申请回调和状态通知回调 cp_extra 会是空值。 | |||
| * - 外部退款单号说明 | |||
| * - 已经在担保支付或者交易1.0使用过的外部退款单号,请不要在交易2.0使用,当交易2.0系统发现该外部退款单号已经在担保支付或者交易1.0创建过退款单号时,会拒绝创建退款单。 | |||
| * - 已经升级到交易2.0的接口之后,不支持再降级使用交易1.0,否则产生的后果由开发者承担。 | |||
| */ | |||
| TtPayRefundV2Result refundV2(TtPayRefundV2Request request) throws TtPayException; | |||
| /** | |||
| * 5. 退款申请回调 | |||
| * 当用户从交易的模板组件发起退款后,抖音开平交易系统会给向开发者的服务发起请求,用于通知开发者用户发起退款,开发者响应时需要返回必填的信息。 | |||
| * 注意 | |||
| * - 退款单的创建是在退款申请回调之前,退款申请回调请求开发者服务失败,也不会在C端展示错误,退款申请回调请求失败后会进行重试。 | |||
| * - 请务必确保退款申请回调请求能按照正确的格式和参数要求返回。 | |||
| * - 请求返回的外部退款单号也务必确保在同一小程序内不会重复,否则也会被认为请求失败。 | |||
| * - 开发者返回的err_no 不为 0 也会认为请求失败,会进行重试,请确保请求成功,有拒绝退款的场景请在退款审核阶段拒绝退款。 | |||
| * - 如果一直请求开发者服务失败,退款单将无法被推进到退款审核阶段,请务必确保响应无问题。 | |||
| * - 退款申请回调务必做好幂等处理,相同的系统退款单号重复请求应当被视为相同的一次退款。 | |||
| * | |||
| */ | |||
| RefundOrderCallback refundOrderNotifyV2Result(String notifyData, SignatureHeader header) throws TtPayException; | |||
| /** | |||
| * 退款审核结果同步 | |||
| * @param request | |||
| * @return | |||
| * @throws TtPayException | |||
| */ | |||
| boolean merchantAuditCallback(TtRefundAuditMsgRequest request) throws TtPayException; | |||
| /** | |||
| * <pre> | |||
| * 查询退款 | |||
| * | |||
| */ | |||
| TtPayRefundQueryV2Result refundQueryV2(TtPayRefundQueryV2Request request) throws TtPayException; | |||
| /** | |||
| * 获取微信请求数据,方便接口调用方获取处理. | |||
| * | |||
| * @return the wx api data | |||
| */ | |||
| WxPayApiData getWxApiData(); | |||
| } | |||
| @@ -0,0 +1,216 @@ | |||
| package com.iformall.douyin.pay.exception; | |||
| import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; | |||
| import com.google.common.base.Joiner; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| /** | |||
| * <pre> | |||
| * 支付异常结果类 | |||
| * Created by Binary Wang on 2017-6-6. | |||
| * </pre> | |||
| * | |||
| * @author BinaryWang | |||
| */ | |||
| @Data | |||
| @EqualsAndHashCode(callSuper = false) | |||
| public class TtPayException extends Exception { | |||
| private static final long serialVersionUID = -1246675502834889819L; | |||
| /** | |||
| * 自定义错误讯息. | |||
| */ | |||
| private String customErrorMsg; | |||
| /** | |||
| * 返回状态码. | |||
| */ | |||
| private String returnCode; | |||
| /** | |||
| * 返回信息. | |||
| */ | |||
| private String returnMsg; | |||
| /** | |||
| * 业务结果. | |||
| */ | |||
| private String resultCode; | |||
| /** | |||
| * 错误代码. | |||
| */ | |||
| private String errCode; | |||
| /** | |||
| * 错误代码描述. | |||
| */ | |||
| private String errCodeDes; | |||
| /** | |||
| * 微信支付返回的结果xml字符串. | |||
| */ | |||
| private String xmlString; | |||
| /** | |||
| * Instantiates a new Wx pay exception. | |||
| * | |||
| * @param customErrorMsg the custom error msg | |||
| */ | |||
| public TtPayException(String customErrorMsg) { | |||
| super(customErrorMsg); | |||
| this.customErrorMsg = customErrorMsg; | |||
| } | |||
| /** | |||
| * Instantiates a new Wx pay exception. | |||
| * | |||
| * @param customErrorMsg the custom error msg | |||
| * @param tr the tr | |||
| */ | |||
| public TtPayException(String customErrorMsg, Throwable tr) { | |||
| super(customErrorMsg, tr); | |||
| this.customErrorMsg = customErrorMsg; | |||
| } | |||
| private TtPayException(Builder builder) { | |||
| super(builder.buildErrorMsg()); | |||
| returnCode = builder.returnCode; | |||
| returnMsg = builder.returnMsg; | |||
| resultCode = builder.resultCode; | |||
| errCode = builder.errCode; | |||
| errCodeDes = builder.errCodeDes; | |||
| xmlString = builder.xmlString; | |||
| } | |||
| /** | |||
| * 通过BaseWxPayResult生成异常对象. | |||
| * | |||
| * @param payBaseResult the pay base result | |||
| * @return the wx pay exception | |||
| */ | |||
| public static TtPayException from(BaseWxPayResult payBaseResult) { | |||
| return TtPayException.newBuilder() | |||
| .xmlString(payBaseResult.getXmlString()) | |||
| .returnMsg(payBaseResult.getReturnMsg()) | |||
| .returnCode(payBaseResult.getReturnCode()) | |||
| .resultCode(payBaseResult.getResultCode()) | |||
| .errCode(payBaseResult.getErrCode()) | |||
| .errCodeDes(payBaseResult.getErrCodeDes()) | |||
| .build(); | |||
| } | |||
| /** | |||
| * New builder builder. | |||
| * | |||
| * @return the builder | |||
| */ | |||
| public static Builder newBuilder() { | |||
| return new Builder(); | |||
| } | |||
| /** | |||
| * The type Builder. | |||
| */ | |||
| public static final class Builder { | |||
| private String returnCode; | |||
| private String returnMsg; | |||
| private String resultCode; | |||
| private String errCode; | |||
| private String errCodeDes; | |||
| private String xmlString; | |||
| private Builder() { | |||
| } | |||
| /** | |||
| * Return code builder. | |||
| * | |||
| * @param returnCode the return code | |||
| * @return the builder | |||
| */ | |||
| public Builder returnCode(String returnCode) { | |||
| this.returnCode = returnCode; | |||
| return this; | |||
| } | |||
| /** | |||
| * Return msg builder. | |||
| * | |||
| * @param returnMsg the return msg | |||
| * @return the builder | |||
| */ | |||
| public Builder returnMsg(String returnMsg) { | |||
| this.returnMsg = returnMsg; | |||
| return this; | |||
| } | |||
| /** | |||
| * Result code builder. | |||
| * | |||
| * @param resultCode the result code | |||
| * @return the builder | |||
| */ | |||
| public Builder resultCode(String resultCode) { | |||
| this.resultCode = resultCode; | |||
| return this; | |||
| } | |||
| /** | |||
| * Err code builder. | |||
| * | |||
| * @param errCode the err code | |||
| * @return the builder | |||
| */ | |||
| public Builder errCode(String errCode) { | |||
| this.errCode = errCode; | |||
| return this; | |||
| } | |||
| /** | |||
| * Err code des builder. | |||
| * | |||
| * @param errCodeDes the err code des | |||
| * @return the builder | |||
| */ | |||
| public Builder errCodeDes(String errCodeDes) { | |||
| this.errCodeDes = errCodeDes; | |||
| return this; | |||
| } | |||
| /** | |||
| * Xml string builder. | |||
| * | |||
| * @param xmlString the xml string | |||
| * @return the builder | |||
| */ | |||
| public Builder xmlString(String xmlString) { | |||
| this.xmlString = xmlString; | |||
| return this; | |||
| } | |||
| /** | |||
| * Build wx pay exception. | |||
| * | |||
| * @return the wx pay exception | |||
| */ | |||
| public TtPayException build() { | |||
| return new TtPayException(this); | |||
| } | |||
| /** | |||
| * Build error msg string. | |||
| * | |||
| * @return the string | |||
| */ | |||
| public String buildErrorMsg() { | |||
| return Joiner.on(",").skipNulls().join( | |||
| returnCode == null ? null : String.format("返回代码:[%s]", returnCode), | |||
| returnMsg == null ? null : String.format("返回信息:[%s]", returnMsg), | |||
| resultCode == null ? null : String.format("结果代码:[%s]", resultCode), | |||
| errCode == null ? null : String.format("错误代码:[%s]", errCode), | |||
| errCodeDes == null ? null : String.format("错误详情:[%s]", errCodeDes), | |||
| xmlString == null ? null : "返回的原始报文:\n" + xmlString | |||
| ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,255 @@ | |||
| package com.iformall.douyin.pay.impl; | |||
| import com.alibaba.fastjson.TypeReference; | |||
| import com.github.binarywang.wxpay.bean.WxPayApiData; | |||
| import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||
| import com.github.binarywang.wxpay.exception.WxPayException; | |||
| import com.github.binarywang.wxpay.v3.util.AesUtils; | |||
| import com.google.gson.Gson; | |||
| import com.google.gson.GsonBuilder; | |||
| import com.iformall.douyin.pay.ProfitSharingV2Service; | |||
| import com.iformall.douyin.pay.TtPayService; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import com.iformall.douyin.payv2.config.TtPayConfig; | |||
| import com.iformall.douyin.payv2.request.*; | |||
| import com.iformall.douyin.payv2.result.*; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import java.io.IOException; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.security.GeneralSecurityException; | |||
| import java.util.*; | |||
| /** | |||
| * <pre> | |||
| * 支付接口请求抽象实现类 | |||
| * Created by Binary Wang on 2017-7-8. | |||
| * </pre> | |||
| * | |||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
| */ | |||
| public abstract class BaseTtPayServiceImpl implements TtPayService { | |||
| private static final String TOTAL_FUND_COUNT = "资金流水总笔数"; | |||
| /** | |||
| * The Log. | |||
| */ | |||
| final Logger log = LoggerFactory.getLogger(this.getClass()); | |||
| private static final Gson GSON = new GsonBuilder().create(); | |||
| /** | |||
| * The constant wxApiData. | |||
| */ | |||
| static ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>(); | |||
| private ProfitSharingV2Service profitSharingV2Service = new ProfitSharingV2ServiceImpl(this); | |||
| /** | |||
| * The Config. | |||
| */ | |||
| protected TtPayConfig config; | |||
| @Override | |||
| public ProfitSharingV2Service getProfitSharingV2Service() { | |||
| return profitSharingV2Service; | |||
| } | |||
| @Override | |||
| public TtPayConfig getConfig() { | |||
| return this.config; | |||
| } | |||
| @Override | |||
| public void setConfig(TtPayConfig config) { | |||
| this.config = config; | |||
| } | |||
| @Override | |||
| public String getPayBaseUrl() { | |||
| return this.getConfig().getPayBaseUrl(); | |||
| } | |||
| @Override | |||
| public boolean callbackSettings(CallBackSettingsRequest request) throws TtPayException { | |||
| String url = String.format("%s/api/apps/trade/v2/settings", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(response, BaseTtPayResult.class); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return true; | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public CallBackSettingsRequest querySettings() throws TtPayException { | |||
| String url = String.format("%s/api/apps/trade/v2/query_settings", this.getPayBaseUrl()); | |||
| String response = this.postV2(url,""); | |||
| BaseTtPayResult<CallBackSettingsRequest> baseTtPayResult = GSON.fromJson(response, | |||
| new TypeReference<BaseTtPayResult<CallBackSettingsRequest>>(){}.getType()); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return baseTtPayResult.getData(); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public CreateOrderCallback parseOrderNotifyV2Result(String notifyData, SignatureHeader header) throws TtPayException { | |||
| if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) { | |||
| throw new TtPayException("非法请求,头部信息验证失败"); | |||
| } | |||
| OriginNotifyResponse response = GSON.fromJson(notifyData, OriginNotifyResponse.class); | |||
| try { | |||
| CreateOrderCallback createOrderCallback = GSON.fromJson(response.getMsg(), CreateOrderCallback.class); | |||
| return createOrderCallback; | |||
| } catch (Exception e) { | |||
| throw new TtPayException("解析报文异常!", e); | |||
| } | |||
| } | |||
| /** | |||
| * 校验通知签名 | |||
| * | |||
| * @param header 通知头信息 | |||
| * @param data 通知数据 | |||
| * @return true:校验通过 false:校验不通过 | |||
| */ | |||
| private boolean verifyNotifySign(SignatureHeader header, String data) { | |||
| String beforeSign = String.format("%s\n%s\n%s\n", | |||
| header.getTimeStamp(), | |||
| header.getNonce(), | |||
| data); | |||
| return this.getConfig().getVerifier().verify( | |||
| beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned()); | |||
| } | |||
| @Override | |||
| public TtPayUnifiedOrderV2Result createOrderV2(TtPayUnifiedOrderV2Request request) throws TtPayException{ | |||
| String url = String.format("%s/api/apps/trade/v2/create_order", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult<TtPayUnifiedOrderV2Result> baseTtPayResult = GSON.fromJson(response, | |||
| new TypeReference<BaseTtPayResult<TtPayUnifiedOrderV2Result>>(){}.getType()); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return baseTtPayResult.getData(); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public TtPayOrderQueryV2Result queryOrderV2(String orderId, String outOrderNo) throws TtPayException { | |||
| TtPayOrderQueryV2Request request = new TtPayOrderQueryV2Request(); | |||
| request.setOutOrderNo(StringUtils.trimToNull(outOrderNo)); | |||
| request.setOrderId(StringUtils.trimToNull(orderId)); | |||
| return this.queryOrderV2(request); | |||
| } | |||
| @Override | |||
| public TtPayOrderQueryV2Result queryOrderV2(TtPayOrderQueryV2Request request) throws TtPayException { | |||
| String url = String.format("%s/api/apps/trade/v2/query_order", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult<TtPayOrderQueryV2Result> baseTtPayResult = GSON.fromJson(response, | |||
| new TypeReference<BaseTtPayResult<TtPayOrderQueryV2Result>>(){}.getType()); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return baseTtPayResult.getData(); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| public TtPayCpsOrderQueryV2Result queryCpsOrderV2(String orderId, String outOrderNo) throws TtPayException{ | |||
| String url = String.format("%s/api/apps/trade/v2/query_cps", this.getPayBaseUrl()); | |||
| TtPayOrderQueryV2Request request = new TtPayOrderQueryV2Request(); | |||
| request.setOutOrderNo(StringUtils.trimToNull(outOrderNo)); | |||
| request.setOrderId(StringUtils.trimToNull(orderId)); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult<TtPayCpsOrderQueryV2Result> baseTtPayResult = GSON.fromJson(response, | |||
| new TypeReference<BaseTtPayResult<TtPayCpsOrderQueryV2Result>>(){}.getType()); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return baseTtPayResult.getData(); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean pushDelivery(TtOrderPushDeliveryRequest request) throws TtPayException{ | |||
| String url = String.format("%s/api/apps/trade/v2/push_delivery", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(response, BaseTtPayResult.class); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return true; | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public TtPayRefundV2Result refundV2(TtPayRefundV2Request request) throws TtPayException { | |||
| String url = String.format("%s/api/apps/trade/v2/create_refund", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult<TtPayRefundV2Result> baseTtPayResult = GSON.fromJson(response, | |||
| new TypeReference<BaseTtPayResult<TtPayRefundV2Result>>(){}.getType()); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return baseTtPayResult.getData(); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public RefundOrderCallback refundOrderNotifyV2Result(String notifyData, SignatureHeader header) throws TtPayException { | |||
| if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) { | |||
| throw new TtPayException("非法请求,头部信息验证失败"); | |||
| } | |||
| OriginNotifyResponse response = GSON.fromJson(notifyData, OriginNotifyResponse.class); | |||
| try { | |||
| RefundOrderCallback refundOrderCallback = GSON.fromJson(response.getMsg(), RefundOrderCallback.class); | |||
| return refundOrderCallback; | |||
| } catch (Exception e) { | |||
| throw new TtPayException("解析报文异常!", e); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean merchantAuditCallback(TtRefundAuditMsgRequest request) throws TtPayException{ | |||
| String url = String.format("%s/api/apps/trade/v2/merchant_audit_callback", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(response, BaseTtPayResult.class); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return true; | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public TtPayRefundQueryV2Result refundQueryV2(TtPayRefundQueryV2Request request) throws TtPayException{ | |||
| String url = String.format("%s/api/apps/trade/v2/query_refund", this.getPayBaseUrl()); | |||
| String response = this.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult<TtPayRefundQueryV2Result> baseTtPayResult = GSON.fromJson(response, | |||
| new TypeReference<BaseTtPayResult<TtPayRefundQueryV2Result>>(){}.getType()); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| return baseTtPayResult.getData(); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public WxPayApiData getWxApiData() { | |||
| try { | |||
| return wxApiData.get(); | |||
| } finally { | |||
| //一般来说,接口请求会在一个线程内进行,这种情况下,每个线程get的会是之前所存入的数据, | |||
| // 但以防万一有同一线程多次请求的问题,所以每次获取完数据后移除对应数据 | |||
| wxApiData.remove(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| package com.iformall.douyin.pay.impl; | |||
| import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||
| import com.google.gson.Gson; | |||
| import com.google.gson.GsonBuilder; | |||
| import com.google.gson.JsonObject; | |||
| import com.iformall.douyin.pay.ProfitSharingV2Service; | |||
| import com.iformall.douyin.pay.TtPayService; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import com.iformall.douyin.payv2.auth.Verifier; | |||
| import com.iformall.douyin.payv2.request.ProfitSharingRequest; | |||
| import com.iformall.douyin.payv2.result.BaseTtPayResult; | |||
| import com.iformall.douyin.payv2.result.ProfitSharingResult; | |||
| import lombok.RequiredArgsConstructor; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import me.chanjar.weixin.common.util.json.GsonHelper; | |||
| import java.nio.charset.StandardCharsets; | |||
| /** | |||
| * 支付V2-资金应用-分账Service | |||
| * | |||
| * @author pg 2021-6-23 | |||
| * @version 1.0 | |||
| */ | |||
| @Slf4j | |||
| @RequiredArgsConstructor | |||
| public class ProfitSharingV2ServiceImpl implements ProfitSharingV2Service { | |||
| private static final Gson GSON = new GsonBuilder().create(); | |||
| private final TtPayService payService; | |||
| @Override | |||
| public String profitSharing(ProfitSharingRequest request) throws TtPayException { | |||
| String url = String.format("%s/api/apps/trade/v2/create_settle", this.payService.getPayBaseUrl()); | |||
| String result = this.payService.postV2(url, GSON.toJson(request)); | |||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(result, BaseTtPayResult.class); | |||
| if(baseTtPayResult.isSuccess()){ | |||
| Object data = baseTtPayResult.getData(); | |||
| JsonObject asJsonObject = GSON.toJsonTree(data).getAsJsonObject(); | |||
| return GsonHelper.getString(asJsonObject,"settle_id"); | |||
| }else{ | |||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||
| } | |||
| } | |||
| @Override | |||
| public ProfitSharingResult getProfitSharingResult(String out_settle_no) throws TtPayException { | |||
| String url = String.format("%s/api/apps/trade/v2/query_settle", this.payService.getPayBaseUrl()); | |||
| JsonObject jsonObject = new JsonObject(); | |||
| jsonObject.addProperty("out_settle_no",out_settle_no); | |||
| String result = this.payService.postV2(url,jsonObject.toString()); | |||
| return GSON.fromJson(result, ProfitSharingResult.class); | |||
| } | |||
| /** | |||
| * 校验通知签名 | |||
| * | |||
| * @param header 通知头信息 | |||
| * @param data 通知数据 | |||
| * @return true:校验通过 false:校验不通过 | |||
| */ | |||
| private boolean verifyNotifySign(SignatureHeader header, String data) throws TtPayException { | |||
| String beforeSign = String.format("%s\n%s\n%s\n", | |||
| header.getTimeStamp(), | |||
| header.getNonce(), | |||
| data); | |||
| Verifier verifier = this.payService.getConfig().getVerifier(); | |||
| if (verifier == null) { | |||
| throw new TtPayException("检验对象为空"); | |||
| } | |||
| return verifier.verify( | |||
| beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,155 @@ | |||
| package com.iformall.douyin.pay.impl; | |||
| import com.google.gson.JsonElement; | |||
| import com.google.gson.JsonObject; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import me.chanjar.weixin.common.util.json.GsonParser; | |||
| import org.apache.http.HttpStatus; | |||
| 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.client.methods.HttpPost; | |||
| import org.apache.http.client.methods.HttpRequestBase; | |||
| import org.apache.http.entity.StringEntity; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import org.apache.http.util.EntityUtils; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.nio.charset.StandardCharsets; | |||
| /** | |||
| * <pre> | |||
| * 支付请求实现类,apache httpclient实现. | |||
| * Created by Binary Wang on 2016/7/28. | |||
| * </pre> | |||
| * | |||
| */ | |||
| public class TtPayServiceApacheHttpImpl extends BaseTtPayServiceImpl { | |||
| @Override | |||
| public String postV2(String url, String requestStr) throws TtPayException { | |||
| CloseableHttpClient httpClient = this.createApiV2HttpClient(); | |||
| HttpPost httpPost = this.createHttpPost(url, requestStr); | |||
| httpPost.addHeader("Accept", "application/json"); | |||
| httpPost.addHeader("Content-Type", "application/json"); | |||
| try (CloseableHttpResponse response = httpClient.execute(httpPost)) { | |||
| //v3已经改为通过状态码判断200 204 成功 | |||
| int statusCode = response.getStatusLine().getStatusCode(); | |||
| //post方法有可能会没有返回值的情况 | |||
| String responseString; | |||
| if (response.getEntity() == null) { | |||
| responseString = null; | |||
| } else { | |||
| responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); | |||
| } | |||
| if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) { | |||
| this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString); | |||
| return responseString; | |||
| } else { | |||
| //有错误提示信息返回 | |||
| JsonObject jsonObject = GsonParser.parse(responseString); | |||
| throw convertException(jsonObject); | |||
| } | |||
| } catch (Exception e) { | |||
| this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); | |||
| throw (e instanceof TtPayException) ? (TtPayException) e : new TtPayException(e.getMessage(), e); | |||
| } finally { | |||
| httpPost.releaseConnection(); | |||
| } | |||
| } | |||
| @Override | |||
| public String postV2(String url, HttpPost httpPost) throws TtPayException { | |||
| return this.requestV2(url, httpPost); | |||
| } | |||
| @Override | |||
| public String requestV2(String url, HttpRequestBase httpRequest) throws TtPayException { | |||
| httpRequest.setConfig(RequestConfig.custom() | |||
| .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout()) | |||
| .setConnectTimeout(this.getConfig().getHttpConnectionTimeout()) | |||
| .setSocketTimeout(this.getConfig().getHttpTimeout()) | |||
| .build()); | |||
| CloseableHttpClient httpClient = this.createApiV2HttpClient(); | |||
| try (CloseableHttpResponse response = httpClient.execute(httpRequest)) { | |||
| //v3已经改为通过状态码判断200 204 成功 | |||
| int statusCode = response.getStatusLine().getStatusCode(); | |||
| //post方法有可能会没有返回值的情况 | |||
| String responseString; | |||
| if (response.getEntity() == null) { | |||
| responseString = null; | |||
| } else { | |||
| responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); | |||
| } | |||
| if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) { | |||
| this.log.info("\n【请求地址】:{}\n【响应数据】:{}", url, responseString); | |||
| return responseString; | |||
| } else { | |||
| //有错误提示信息返回 | |||
| JsonObject jsonObject = GsonParser.parse(responseString); | |||
| throw convertException(jsonObject); | |||
| } | |||
| } catch (Exception e) { | |||
| this.log.error("\n【请求地址】:{}\n【异常信息】:{}", url, e.getMessage()); | |||
| throw (e instanceof TtPayException) ? (TtPayException) e : new TtPayException(e.getMessage(), e); | |||
| } finally { | |||
| httpRequest.releaseConnection(); | |||
| } | |||
| } | |||
| @Override | |||
| public String getV2(String url) throws TtPayException { | |||
| HttpGet httpGet = new HttpGet(url); | |||
| httpGet.addHeader("Accept", "application/json"); | |||
| httpGet.addHeader("Content-Type", "application/json"); | |||
| return this.requestV2(url.toString(), httpGet); | |||
| } | |||
| private CloseableHttpClient createApiV2HttpClient() throws TtPayException { | |||
| CloseableHttpClient apiV3HttpClient = this.getConfig().getApiV2HttpClient(); | |||
| if (null == apiV3HttpClient) { | |||
| return this.getConfig().initApiV2HttpClient(); | |||
| } | |||
| return apiV3HttpClient; | |||
| } | |||
| private StringEntity createEntry(String requestStr) { | |||
| try { | |||
| return new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)); | |||
| } catch (UnsupportedEncodingException e) { | |||
| //cannot happen | |||
| this.log.error(e.getMessage(), e); | |||
| return null; | |||
| } | |||
| } | |||
| private HttpPost createHttpPost(String url, String requestStr) { | |||
| HttpPost httpPost = new HttpPost(url); | |||
| httpPost.setEntity(this.createEntry(requestStr)); | |||
| httpPost.setConfig(RequestConfig.custom() | |||
| .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout()) | |||
| .setConnectTimeout(this.getConfig().getHttpConnectionTimeout()) | |||
| .setSocketTimeout(this.getConfig().getHttpTimeout()) | |||
| .build()); | |||
| return httpPost; | |||
| } | |||
| private TtPayException convertException(JsonObject jsonObject) { | |||
| //todo 这里考虑使用新的适用于V2的异常 | |||
| JsonElement codeElement = jsonObject.get("code"); | |||
| String code = codeElement == null ? null : codeElement.getAsString(); | |||
| String message = jsonObject.get("message").getAsString(); | |||
| TtPayException ttPayException = new TtPayException(message); | |||
| ttPayException.setErrCode(code); | |||
| ttPayException.setErrCodeDes(message); | |||
| return ttPayException; | |||
| } | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| package com.iformall.douyin.pay.impl; | |||
| /** | |||
| * <pre> | |||
| * 支付接口请求实现类,默认使用Apache HttpClient实现 | |||
| * Created by Binary Wang on 2017-7-8. | |||
| * </pre> | |||
| * | |||
| */ | |||
| public class TtPayServiceImpl extends TtPayServiceApacheHttpImpl { | |||
| } | |||
| @@ -0,0 +1,72 @@ | |||
| package com.iformall.douyin.payv2.auth; | |||
| import com.iformall.douyin.payv2.util.PemUtils; | |||
| import me.chanjar.weixin.common.error.WxRuntimeException; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.security.*; | |||
| import java.util.Base64; | |||
| public class CertificatesVerifier implements Verifier { | |||
| private PublicKey apiKey; | |||
| public CertificatesVerifier(PublicKey apiKey) { | |||
| this.apiKey = apiKey; | |||
| } | |||
| @Override | |||
| public boolean verify(byte[] message, String signature) { | |||
| try { | |||
| Signature sign = Signature.getInstance("SHA256withRSA"); | |||
| sign.initVerify(this.apiKey); | |||
| sign.update(message); | |||
| return sign.verify(Base64.getDecoder().decode(signature.getBytes(StandardCharsets.UTF_8))); | |||
| } catch (NoSuchAlgorithmException e) { | |||
| throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e); | |||
| } catch (SignatureException e) { | |||
| throw new WxRuntimeException("签名验证过程发生了错误", e); | |||
| } catch (InvalidKeyException e) { | |||
| throw new WxRuntimeException("无效的证书", e); | |||
| } | |||
| } | |||
| // public static void main(String[] args) { | |||
| // String pubKey = "-----BEGIN PUBLIC KEY-----\n" + | |||
| // "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8jSFriZ6l5vv0xVcpFJ\n" + | |||
| // "NxihPh3j6tVKrU2FBythCstyr/CwdpAp9AGXvcaW2x2kKiOMXXaRDo6OysjggsxK\n" + | |||
| // "5hh1fWDE3ML4Wi5tfAV64pvj8wn5XeHXGKtXcKD/ASQmUGnMKI0g8i2REm3Q7gzy\n" + | |||
| // "JH35URh+tU8wI2v8mDY9OCZ7Hmu8ImW3pibyYRYK0CEpa31+65gVaTeoaPlqTKR0\n" + | |||
| // "rwgxZM5nFcXxGtiTsH0O1GAJBqWpyVeOqH19vEVB/bROEb21bf65ZYhac2Z1lzWq\n" + | |||
| // "MW+/4knIDg6EH3/xZWFPPwAFZgpfkSQES/twPkN/59cZ8SfTwJ84k/KUOApvkihM\n" + | |||
| // "uQIDAQAB\n" + | |||
| // "-----END PUBLIC KEY-----"; | |||
| // String timestamp = "1653906762"; | |||
| // String nonce = "pztVmu9EhPgCv9Dvw31t68U9WhMcLXCb"; | |||
| // String httpBody = "{\"err_no\":0,\"data\":{\"create_order_callback\":\"https://ctest.malls.iformall.com/C/api/order/douyinPushOrder\",\"refund_callback\":\"https://ctest.malls.iformall.com/C/api/order/douyinRefundOrder\",\"delivery_qrcode_redirect\":\"\"},\"resp_extra\":{\"logid\":\"202205301832420101581160381B3C09C0\"},\"err_tips\":\"success\"}"; | |||
| // String signStr = "pZEQga7EpGI+NXEznLNZROViIBxwWaofnlstthQsu8MZiuTRUtool2SQhfLHkXwYzj5O8yj+luTbFUrhTfX+BzvcR3+fGrqMtgqGWp86a1hAg4e4pvoTHd5PAxUGRDb/gGxPoxLDgrS6cLKusdGi6mmwJbERveD9ThNV1RQGQo/BM3BeImr3fYdJ/ZU67iVkP6SEWkqRiEJhnQMaavy/B4LK3xI0A5BhWlGbhGUIqumLT903tIOhofXGA6PQJbDiU38J5EtMj/Z7l6+IXtbA/KO0IWbIZ96KFs6e8ZE6H18Xn7b0J7KDTjTelMt7iXczrLU2/e3QEcfn2/7+7DIRMQ=="; | |||
| // | |||
| // StringBuffer buffer = new StringBuffer(); | |||
| // buffer.append(timestamp).append("\n"); | |||
| // buffer.append(nonce).append("\n"); | |||
| // buffer.append(httpBody).append("\n"); | |||
| // try { | |||
| // Signature sign = Signature.getInstance("SHA256withRSA"); | |||
| // sign.initVerify(PemUtils.loadPublicKey(new ByteArrayInputStream(pubKey.getBytes("utf-8")))); | |||
| // sign.update(buffer.toString().getBytes(StandardCharsets.UTF_8)); | |||
| // boolean verify = sign.verify(Base64.getDecoder().decode(signStr.getBytes(StandardCharsets.UTF_8))); | |||
| // System.out.println("-------"+verify); | |||
| // } catch (NoSuchAlgorithmException e) { | |||
| // e.printStackTrace(); | |||
| // } catch (UnsupportedEncodingException e) { | |||
| // e.printStackTrace(); | |||
| // } catch (SignatureException e) { | |||
| // e.printStackTrace(); | |||
| // } catch (InvalidKeyException e) { | |||
| // e.printStackTrace(); | |||
| // } | |||
| // } | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| package com.iformall.douyin.payv2.auth; | |||
| import me.chanjar.weixin.common.error.WxRuntimeException; | |||
| import java.security.*; | |||
| import java.util.Base64; | |||
| public class PrivateKeySigner implements Signer { | |||
| private String certificateSerialNumber; | |||
| private PrivateKey privateKey; | |||
| public PrivateKeySigner(String serialNumber, PrivateKey privateKey) { | |||
| this.certificateSerialNumber = serialNumber; | |||
| this.privateKey = privateKey; | |||
| } | |||
| @Override | |||
| public SignatureResult sign(byte[] message) { | |||
| try { | |||
| Signature sign = Signature.getInstance("SHA256withRSA"); | |||
| sign.initSign(privateKey); | |||
| sign.update(message); | |||
| return new SignatureResult( | |||
| Base64.getEncoder().encodeToString(sign.sign()), certificateSerialNumber); | |||
| } catch (NoSuchAlgorithmException e) { | |||
| throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e); | |||
| } catch (SignatureException e) { | |||
| throw new WxRuntimeException("签名计算失败", e); | |||
| } catch (InvalidKeyException e) { | |||
| throw new WxRuntimeException("无效的私钥", e); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| package com.iformall.douyin.payv2.auth; | |||
| public interface Signer { | |||
| SignatureResult sign(byte[] message); | |||
| class SignatureResult { | |||
| String sign; | |||
| String certificateSerialNumber; | |||
| public SignatureResult(String sign, String serialNumber) { | |||
| this.sign = sign; | |||
| this.certificateSerialNumber = serialNumber; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,91 @@ | |||
| package com.iformall.douyin.payv2.auth; | |||
| import com.iformall.douyin.payv2.util.Credentials; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.apache.http.HttpEntityEnclosingRequest; | |||
| import org.apache.http.client.methods.HttpRequestWrapper; | |||
| import org.apache.http.util.EntityUtils; | |||
| import java.io.IOException; | |||
| import java.net.URI; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.security.SecureRandom; | |||
| @Slf4j | |||
| public class TtPayCredentials implements Credentials { | |||
| private static final String SYMBOLS = | |||
| "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |||
| private static final SecureRandom RANDOM = new SecureRandom(); | |||
| protected String appId; | |||
| protected Signer signer; | |||
| public TtPayCredentials(String appId, Signer signer) { | |||
| this.appId = appId; | |||
| this.signer = signer; | |||
| } | |||
| public String getAppId() { | |||
| return appId; | |||
| } | |||
| protected long generateTimestamp() { | |||
| return System.currentTimeMillis() / 1000; | |||
| } | |||
| protected String generateNonceStr() { | |||
| char[] nonceChars = new char[32]; | |||
| for (int index = 0; index < nonceChars.length; ++index) { | |||
| nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length())); | |||
| } | |||
| return new String(nonceChars); | |||
| } | |||
| @Override | |||
| public final String getSchema() { | |||
| return "SHA256-RSA2048"; | |||
| } | |||
| @Override | |||
| public final String getToken(HttpRequestWrapper request) throws IOException { | |||
| String nonceStr = generateNonceStr(); | |||
| long timestamp = generateTimestamp(); | |||
| String message = buildMessage(nonceStr, timestamp, request); | |||
| log.info("authorization message=[{}]", message); | |||
| // System.out.println("message---------------------------"+message); | |||
| Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8)); | |||
| String token = "appid=\"" + getAppId() + "\"," | |||
| + "nonce_str=\"" + nonceStr + "\"," | |||
| + "timestamp=\"" + timestamp + "\"," | |||
| + "key_version=\"" + signature.certificateSerialNumber + "\"," | |||
| + "signature=\"" + signature.sign + "\""; | |||
| log.info("authorization token=[{}]", token); | |||
| // System.out.println("token---------------------------"+token); | |||
| return token; | |||
| } | |||
| protected final String buildMessage(String nonce, long timestamp, HttpRequestWrapper request) | |||
| throws IOException { | |||
| URI uri = request.getURI(); | |||
| String canonicalUrl = uri.getRawPath(); | |||
| if (uri.getQuery() != null) { | |||
| canonicalUrl += "?" + uri.getRawQuery(); | |||
| } | |||
| String body = ""; | |||
| // PATCH,POST,PUT | |||
| body = EntityUtils.toString(((HttpEntityEnclosingRequest) request).getEntity(),StandardCharsets.UTF_8); | |||
| return request.getRequestLine().getMethod() + "\n" | |||
| + canonicalUrl + "\n" | |||
| + timestamp + "\n" | |||
| + nonce + "\n" | |||
| + body + "\n"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| package com.iformall.douyin.payv2.auth; | |||
| import com.iformall.douyin.payv2.util.Validator; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.apache.http.Header; | |||
| import org.apache.http.HttpEntity; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.entity.ContentType; | |||
| import org.apache.http.util.EntityUtils; | |||
| import java.io.IOException; | |||
| @Slf4j | |||
| public class TtPayValidator implements Validator { | |||
| private Verifier verifier; | |||
| public TtPayValidator(Verifier verifier) { | |||
| this.verifier = verifier; | |||
| } | |||
| @Override | |||
| public final boolean validate(CloseableHttpResponse response) throws IOException { | |||
| if (!ContentType.APPLICATION_JSON.getMimeType().equals(ContentType.parse(String.valueOf(response.getFirstHeader("Content-Type").getValue())).getMimeType())) { | |||
| return true; | |||
| } | |||
| Header sign = response.getFirstHeader("Byte-Signature"); | |||
| Header timestamp = response.getFirstHeader("Byte-Timestamp"); | |||
| Header nonce = response.getFirstHeader("Byte-Nonce-Str"); | |||
| // todo: check timestamp | |||
| if (timestamp == null || nonce == null || sign == null) { | |||
| return false; | |||
| } | |||
| String message = buildMessage(response); | |||
| return verifier.verify(message.getBytes("utf-8"), sign.getValue()); | |||
| } | |||
| protected final String buildMessage(CloseableHttpResponse response) throws IOException { | |||
| String timestamp = response.getFirstHeader("Byte-Timestamp").getValue(); | |||
| String nonce = response.getFirstHeader("Byte-Nonce-Str").getValue(); | |||
| String body = getResponseBody(response); | |||
| return timestamp + "\n" | |||
| + nonce + "\n" | |||
| + body + "\n"; | |||
| } | |||
| protected final String getResponseBody(CloseableHttpResponse response) throws IOException { | |||
| HttpEntity entity = response.getEntity(); | |||
| return (entity != null && entity.isRepeatable()) ? EntityUtils.toString(entity) : ""; | |||
| } | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| package com.iformall.douyin.payv2.auth; | |||
| public interface Verifier { | |||
| boolean verify(byte[] message, String signature); | |||
| } | |||
| @@ -0,0 +1,179 @@ | |||
| package com.iformall.douyin.payv2.config; | |||
| import com.iformall.douyin.pay.exception.TtPayException; | |||
| import com.iformall.douyin.payv2.auth.CertificatesVerifier; | |||
| import com.iformall.douyin.payv2.auth.TtPayValidator; | |||
| import com.iformall.douyin.payv2.auth.Verifier; | |||
| import com.iformall.douyin.payv2.util.PemUtils; | |||
| import com.iformall.douyin.payv2.util.TtPayV2HttpClientBuilder; | |||
| import jodd.util.ResourcesUtil; | |||
| import lombok.Data; | |||
| import lombok.SneakyThrows; | |||
| import org.apache.commons.lang3.RegExUtils; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import java.io.*; | |||
| import java.net.URL; | |||
| import java.security.PrivateKey; | |||
| import java.security.PublicKey; | |||
| /** | |||
| * 支付配置 | |||
| * | |||
| * @author Binary Wang | |||
| */ | |||
| @Data | |||
| public class TtPayConfig { | |||
| private static final String DEFAULT_PAY_BASE_URL = "https://developer.toutiao.com"; | |||
| private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!"; | |||
| private static final String NOT_FOUND_MSG = "证书文件【%s】不存在,请核实!"; | |||
| /** | |||
| * 支付接口请求地址域名部分. | |||
| */ | |||
| private String payBaseUrl = DEFAULT_PAY_BASE_URL; | |||
| /** | |||
| * http请求连接超时时间. | |||
| */ | |||
| private int httpConnectionTimeout = 5000; | |||
| /** | |||
| * http请求数据读取等待时间. | |||
| */ | |||
| private int httpTimeout = 10000; | |||
| /** | |||
| * appid. | |||
| */ | |||
| private String appId; | |||
| /** | |||
| * apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径. | |||
| */ | |||
| private String privateKeyPath; | |||
| /** | |||
| * api 秘钥值. | |||
| */ | |||
| private String apiKey; | |||
| private Verifier verifier; | |||
| @SneakyThrows | |||
| public Verifier getVerifier() { | |||
| if (verifier == null) { | |||
| //当改对象为null时,初始化api v3的请求头 | |||
| initApiV2HttpClient(); | |||
| } | |||
| return verifier; | |||
| } | |||
| /** | |||
| * apiV2 证书序列号值 | |||
| */ | |||
| private String certSerialNo; | |||
| private CloseableHttpClient apiV2HttpClient; | |||
| /** | |||
| * 私钥信息 | |||
| */ | |||
| private PrivateKey privateKey; | |||
| /** | |||
| * 返回所设置的微信支付接口请求地址域名. | |||
| * | |||
| * @return 微信支付接口请求地址域名 | |||
| */ | |||
| public String getPayBaseUrl() { | |||
| if (StringUtils.isEmpty(this.payBaseUrl)) { | |||
| return DEFAULT_PAY_BASE_URL; | |||
| } | |||
| return this.payBaseUrl; | |||
| } | |||
| /** | |||
| * 初始化api v2请求头 自动签名验签 | |||
| * | |||
| * @return org.apache.http.impl.client.CloseableHttpClient | |||
| * @author doger.wang | |||
| **/ | |||
| public CloseableHttpClient initApiV2HttpClient() throws TtPayException { | |||
| String privateKeyPath = this.getPrivateKeyPath(); | |||
| String apiKey = this.getApiKey(); | |||
| if (StringUtils.isBlank(privateKeyPath)) { | |||
| throw new TtPayException("请确保privateKeyPath已设置"); | |||
| } | |||
| if (StringUtils.isBlank(apiKey)) { | |||
| throw new TtPayException("请确保apiKey值已设置"); | |||
| } | |||
| InputStream keyInputStream = this.loadConfigInputStream(privateKeyPath); | |||
| try { | |||
| PrivateKey privateKey = PemUtils.loadPrivateKey(keyInputStream); | |||
| PublicKey publicKey = PemUtils.loadPublicKey(new ByteArrayInputStream(apiKey.getBytes("utf-8"))); | |||
| CertificatesVerifier certificatesVerifier = new CertificatesVerifier(publicKey); | |||
| CloseableHttpClient httpClient = TtPayV2HttpClientBuilder.create() | |||
| .withAppId(appId, certSerialNo, privateKey) | |||
| .withValidator(new TtPayValidator(certificatesVerifier)) | |||
| .build(); | |||
| this.apiV2HttpClient = httpClient; | |||
| this.privateKey = privateKey; | |||
| this.verifier = certificatesVerifier; | |||
| return httpClient; | |||
| } catch (Exception e) { | |||
| throw new TtPayException("v2请求构造异常!", e); | |||
| } | |||
| } | |||
| /** | |||
| * 从配置路径 加载配置 信息(支持 classpath、本地路径、网络url) | |||
| * @param configPath 配置路径 | |||
| * @return | |||
| * @throws TtPayException | |||
| */ | |||
| private InputStream loadConfigInputStream(String configPath) throws TtPayException { | |||
| InputStream inputStream; | |||
| final String prefix = "classpath:"; | |||
| String fileHasProblemMsg = String.format(PROBLEM_MSG, configPath); | |||
| String fileNotFoundMsg = String.format(NOT_FOUND_MSG, configPath); | |||
| if (configPath.startsWith(prefix)) { | |||
| String path = RegExUtils.removeFirst(configPath, prefix); | |||
| if (!path.startsWith("/")) { | |||
| path = "/" + path; | |||
| } | |||
| try { | |||
| inputStream = ResourcesUtil.getResourceAsStream(path); | |||
| if (inputStream == null) { | |||
| throw new TtPayException(fileNotFoundMsg); | |||
| } | |||
| } catch (Exception e) { | |||
| throw new TtPayException(fileNotFoundMsg, e); | |||
| } | |||
| } else if (configPath.startsWith("http://") || configPath.startsWith("https://")) { | |||
| try { | |||
| inputStream = new URL(configPath).openStream(); | |||
| if (inputStream == null) { | |||
| throw new TtPayException(fileNotFoundMsg); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new TtPayException(fileNotFoundMsg, e); | |||
| } | |||
| } else { | |||
| try { | |||
| File file = new File(configPath); | |||
| if (!file.exists()) { | |||
| throw new TtPayException(fileNotFoundMsg); | |||
| } | |||
| inputStream = new FileInputStream(file); | |||
| } catch (IOException e) { | |||
| throw new TtPayException(fileHasProblemMsg, e); | |||
| } | |||
| } | |||
| return inputStream; | |||
| } | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class CallBackSettingsRequest implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * https回调地址,预下单请求地址,长度限制<=512字节 | |||
| */ | |||
| @SerializedName(value = "create_order_callback") | |||
| private String createOrderCallback; | |||
| /** | |||
| * https回调地址,退款请求地址,长度限制<=512字节 | |||
| */ | |||
| @SerializedName(value = "refund_callback") | |||
| private String refundCallback; | |||
| /** | |||
| * https回调地址,长度限制<=256字节。闭环核销方案核销组件上展示的二维码所对应的跳转地址。开发者可使用这个参数设置app_id维度的订单跳转链接。 | |||
| */ | |||
| @SerializedName(value = "delivery_qrcode_redirect") | |||
| private String deliveryQrcodeRedirect; | |||
| } | |||
| @@ -0,0 +1,67 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.AllArgsConstructor; | |||
| import lombok.Builder; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| /** | |||
| * 请求分账API请求实体 | |||
| * | |||
| * @author pg | |||
| * @date 2021-6-24 | |||
| */ | |||
| @Data | |||
| @Builder(builderMethodName = "newBuilder") | |||
| @NoArgsConstructor | |||
| @AllArgsConstructor | |||
| public class ProfitSharingRequest implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 开发者侧订单id,长度限制<64字节 | |||
| */ | |||
| @SerializedName("out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * 开发者侧分账单id,分账请求的唯一标识,长度限制<64字节 | |||
| */ | |||
| @SerializedName("out_settle_no") | |||
| private String outSettleNo; | |||
| /** | |||
| * 分账描述,长度<512字节 | |||
| */ | |||
| @SerializedName("settle_desc") | |||
| private String settleDesc; | |||
| /** | |||
| * 其他分账方(除卖家之外的),json字符串,长度<512字节 | |||
| * - 示例,"[{\"merchant_uid\":\"分账方商户号1\",\"amount\":100}]" | |||
| * merchant_uid string 是 | |||
| * 进件商户id(除了卖家以外的其他分账方) | |||
| * amount int64 是 | |||
| * 分账金额,单位[分],amount>0 | |||
| */ | |||
| @SerializedName("settle_params") | |||
| private String settleParams; | |||
| /** | |||
| * 透传字段,开发者自定义,<=2048字节,不支持二进制 | |||
| */ | |||
| @SerializedName("cp_extra") | |||
| private String cpExtra; | |||
| /** | |||
| * 分账结果通知地址,必须是https类型, | |||
| * 若不填,默认使用在开发者平台-担保交易配置页面设置的回调地址 | |||
| */ | |||
| @SerializedName("notify_url") | |||
| private String notifyUrl; | |||
| } | |||
| @@ -0,0 +1,73 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 订单推送核销状态请求对象 | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtOrderPushDeliveryRequest implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * <pre> | |||
| * 开发者服务交易单号 | |||
| * </pre> | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * <pre> | |||
| * out_order_no所关联的需要核销的商品单信息,详细结构见下表。可使用此参数指定核销整单中的特定商品单。 | |||
| * 长度<=100 | |||
| * 注意:只有待使用状态的商品单才能核销,已核销、正退款或已退款的将返回错误。 | |||
| * </pre> | |||
| */ | |||
| @SerializedName(value = "item_order_list") | |||
| private List<ItemOrder> itemOrderList; | |||
| /** | |||
| * 是否整单核销。此参数设为true则将out_order_no的所有商品单核销。use_all和item_list必须有一个有效值,要么整单核销,要么指定商品单核销。 | |||
| * 注意:此参数设为true时只有out_order_no的所有商品单都为待使用状态才能成功核销,如果有商品单状态不对将导致不能整单核销,会返回错误。 | |||
| */ | |||
| @SerializedName(value = "use_all") | |||
| private Boolean useAll; | |||
| /** | |||
| * 核销的商铺poi信息,详细结构见下表,最多1024个字节。 | |||
| * 注意:此字段为json string | |||
| * poi_info 结构,poi商品必填所有字段(强校验),小程序商品也尽量传入(不校验) | |||
| * shop_name string poi商品必填 | |||
| * 核销店铺名称,参考商铺同步接口中的店铺名称(name) | |||
| * ext_valid_shop_id string poi商品必填 | |||
| * 核销门店的外部店铺id,参考商铺同步接口中的接入方店铺id(supplier_ext_id) | |||
| * valid_poi_id_str string poi商品必填 | |||
| * 核销门店对应的抖音poi_id,参考商铺同步接口中的抖音poi id(poi_id) | |||
| */ | |||
| @SerializedName(value = "poi_info") | |||
| private String poiInfo; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class ItemOrder implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| } | |||
| } | |||
| @@ -0,0 +1,38 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| /** | |||
| * <pre> | |||
| * 订单查询请求对象 | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtPayOrderQueryV2Request implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * <pre> | |||
| * 抖音开平内部交易订单号,长度<64byte,开发者在接收到抖音开平发起的下单交易回调请求的时候,由抖音开平传递给开发者服务,开发者必须确保将该id与自己平台生成的交易单号进行唯一关联 | |||
| * </pre> | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| private String orderId; | |||
| /** | |||
| * <pre> | |||
| * 开发者系统生成的订单号,与抖音开平交易单号order_id唯一关联,长度<64byte | |||
| * </pre> | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 微信支付-申请退款请求参数 | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtPayRefundQueryV2Request implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 抖音开平内部交易退款单号,长度<= 64byte,开发者必须确保将该id与自己平台生成的交易单号进行唯一关联 | |||
| */ | |||
| @SerializedName(value = "refund_id") | |||
| private String refund_id; | |||
| /** | |||
| * 开发者系统生成的退款单号,与抖音开平退款单号refund_id 唯一关联,长度<= 64byte | |||
| */ | |||
| @SerializedName(value = "out_refund_no") | |||
| private String outRefundNo; | |||
| } | |||
| @@ -0,0 +1,107 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 申请退款请求参数 | |||
| * </pre> | |||
| * | |||
| * @author | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtPayRefundV2Request implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 是 | |||
| * 开发者侧订单号,长度 <= 64 byte | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * 是 | |||
| * 开发者侧退款单号,长度 <= 64 byte | |||
| */ | |||
| @SerializedName(value = "out_refund_no") | |||
| private String outRefundNo; | |||
| /** | |||
| * 否 | |||
| * 开发者自定义透传字段,不支持二进制,长度 <= 2048 byte | |||
| */ | |||
| @SerializedName(value = "cp_extra") | |||
| private String cpExtra; | |||
| /** | |||
| * 是 | |||
| * 退款单的跳转的schema | |||
| */ | |||
| @SerializedName(value = "order_entry_schema") | |||
| private PageEntry orderEntrySchema; | |||
| /** | |||
| * 否 | |||
| * 退款结果通知地址,必须是https类型, | |||
| * 若不填,默认使用在开发者平台-担保交易配置页面设置的退款回调地址 | |||
| */ | |||
| @SerializedName(value = "notify_url") | |||
| private String notifyUrl; | |||
| /** | |||
| * 否(新订单发起退款必传) | |||
| * | |||
| * 需要发起退款的商品单信息(新订单发起退款必传) | |||
| */ | |||
| @SerializedName(value = "item_order_detail") | |||
| private List<OrderDetail> itemOrderDetail; | |||
| /** | |||
| * 否(旧订单发起退款必传) | |||
| * 退款总金额 (旧订单发起退款必传) | |||
| */ | |||
| @SerializedName(value = "refund_total_amount") | |||
| private Integer refundTotalAmount; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class PageEntry implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 路径 没有前导的“/” | |||
| */ | |||
| @SerializedName(value = "path") | |||
| private String path; | |||
| /** | |||
| * 参数 自定义的json结构 | |||
| */ | |||
| @SerializedName(value = "params") | |||
| private String params; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class OrderDetail implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 商品单号,参见前文"对于重要id字段的说明" | |||
| */ | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| } | |||
| } | |||
| @@ -0,0 +1,456 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 统一下单请求参数对象. | |||
| * 参考文档:https://bytedance.feishu.cn/docx/doxcna1ALcy90AGMNdGLoALBeIH#doxcnUUemGYgUYECi8n92wMQQke | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtPayUnifiedOrderV2Request implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 商品信息,详情见 goods_list说明 | |||
| */ | |||
| @SerializedName(value = "goods_list") | |||
| protected List<Good> goodsList; | |||
| /** | |||
| * 是 | |||
| * 订单总价,单位(分) | |||
| */ | |||
| @SerializedName(value = "total_amount") | |||
| private Integer totalAmount; | |||
| /** | |||
| * 否 | |||
| * 用户手机号 | |||
| */ | |||
| @SerializedName(value = "phone_num") | |||
| private String phoneNum; | |||
| /** | |||
| * 否 | |||
| * 用户姓名 | |||
| */ | |||
| @SerializedName(value = "contact_name") | |||
| private String contactName; | |||
| /** | |||
| * 否 | |||
| * 下单备注信息,长度 <= 2048byte | |||
| */ | |||
| @SerializedName(value = "extra") | |||
| private String extra; | |||
| /** | |||
| * 是 | |||
| * 用户OpenID | |||
| */ | |||
| @SerializedName(value = "open_id") | |||
| private String openId; | |||
| /** | |||
| * 否 | |||
| * 支付结果通知地址,必须是https类型。若不填,默认使用在开发者平台-担保交易配置页面设置的支付回调地址 | |||
| */ | |||
| @SerializedName(value = "pay_notify_url") | |||
| private String payNotifyUrl; | |||
| /** | |||
| * 是 | |||
| * 开发者的单号,长度 <= 64 byte | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * 否 | |||
| * 支付超时时间,单位秒,例如300表示300秒后过期;不传或传0会使用默认值300 | |||
| */ | |||
| @SerializedName(value = "pay_expire_seconds") | |||
| private Integer payExpireSeconds; | |||
| /** | |||
| * 是 | |||
| * 订单详情页 | |||
| */ | |||
| @SerializedName(value = "order_entry_schema") | |||
| private PageEntry orderEntrySchema; | |||
| /** | |||
| * 否 | |||
| * 开发者自定义透传字段,不支持二进制,长度 <= 2048 byte | |||
| */ | |||
| @SerializedName(value = "cp_extra") | |||
| private PageEntry cpExtra; | |||
| /** | |||
| * 否 | |||
| * 折扣金额,单位(分) | |||
| */ | |||
| @SerializedName(value = "discount_amount") | |||
| private Integer discountAmount; | |||
| /** | |||
| * 否 | |||
| * 营销算价结果信息, | |||
| */ | |||
| @SerializedName(value = "price_calculation_detail") | |||
| private PriceDetail priceCalculationDetail; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class Good implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 否 | |||
| * - 非poi商品必传 | |||
| * 商品图片链接,长度 <= 512 byte | |||
| */ | |||
| @SerializedName(value = "goods_image") | |||
| private String goodsImage; | |||
| /** | |||
| * 否 | |||
| * - 非poi商品必传 | |||
| * 商品标题/商品名称,长度 <= 256 byte | |||
| */ | |||
| @SerializedName(value = "goods_title") | |||
| private String goodsTitle; | |||
| /** | |||
| * 否 | |||
| * - 非poi商品必传 | |||
| * 商品标签,最多设置三个标签,例如:随时退|免预约|提前3日预约 (“|”是中文类型),详见type的合法值 | |||
| */ | |||
| @SerializedName(value = "labels") | |||
| private String labels; | |||
| /** | |||
| * 否 | |||
| * 使用规则,如 “周一至周日可用”、“周一至周五可用”、“非节假日可用”,默认“周一至周日可用” | |||
| */ | |||
| @SerializedName(value = "date_rule") | |||
| private String dateRule; | |||
| /** | |||
| * 否 | |||
| * - 非poi商品必传 | |||
| * 商品价格,单位(分) | |||
| */ | |||
| @SerializedName(value = "price") | |||
| private Integer price; | |||
| /** | |||
| * 是 | |||
| * 商品数量 | |||
| */ | |||
| @SerializedName(value = "quantity") | |||
| private Integer quantity; | |||
| /** | |||
| * 是 | |||
| * 商品id | |||
| */ | |||
| @SerializedName(value = "goods_id") | |||
| private String goodsId; | |||
| /** | |||
| * 是 | |||
| * 商品id类别,poi商品传 1,非poi商品传 2 | |||
| */ | |||
| @SerializedName(value = "goods_id_type") | |||
| private Integer goodsIdType; | |||
| /** | |||
| * 否 | |||
| * 商品详情页 | |||
| */ | |||
| @SerializedName(value = "goods_page") | |||
| private PageEntry goodsPage; | |||
| /** | |||
| * 否 | |||
| * - 非poi商品必传 | |||
| * 券的有效期,注意: | |||
| * 1. 非poi商品必传,poi商品会从poi库里查询有效期信息,不会使用开发者传的数据 | |||
| * 2. 如果是非poi商品,每个goods_id都要传券的有效期信息,否则会下单失败 | |||
| */ | |||
| @SerializedName(value = "order_valid_time") | |||
| private OrderValid orderValidTime; | |||
| /** | |||
| * 否 | |||
| * 折扣金额,单位(分) | |||
| */ | |||
| @SerializedName(value = "discount_amount") | |||
| private Integer discountAmount; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class PageEntry implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 路径 没有前导的“/” | |||
| */ | |||
| @SerializedName(value = "path") | |||
| private String path; | |||
| /** | |||
| * 参数 自定义的json结构 | |||
| */ | |||
| @SerializedName(value = "params") | |||
| private String params; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class OrderValid implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 券的有效期开始时间,单位毫秒,须大于0 | |||
| */ | |||
| @SerializedName(value = "valid_start_time") | |||
| private Long validStartTime; | |||
| /** | |||
| * 券的有效期结束时间,单位毫秒,须大于0,且须大于valid_start_time和当前时间 | |||
| */ | |||
| @SerializedName(value = "valid_end_time") | |||
| private Long validEndTime; | |||
| /** | |||
| * 1. 券的相对有效时间,单位毫秒,须大于0 | |||
| * 2. 与<valid_start_time,valid_end_time>组合,至少回传一个,否则会下单失败 | |||
| * 3. 都合法优先使用<valid_start_time,valid_end_time>组合 | |||
| * 4. 当valid_duration 有效时,券的有效期开始时间 S=订单支付完成时间,券的有效期结束时间 E=1天 + 向下按天截断(S+valid_duration) | |||
| * eg:valid_duration = 86400000ms(一天) S = 2021.1.1 6:00 E = 2021.1.3 00:00 | |||
| */ | |||
| @SerializedName(value = "valid_duration") | |||
| private Long validDuration; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class PriceDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 算价类型,1-商户单维度,item单价格我们按分摊比例计算, | |||
| * 2-item单维度,item单价格由开发者计算 | |||
| */ | |||
| @SerializedName(value = "calculation_type") | |||
| private Integer calculationType; | |||
| /** | |||
| * 商品算价结果 | |||
| */ | |||
| @SerializedName(value = "goods_discount_detail") | |||
| private List<GoodsDiscountDetail> goodsDiscountDetail; | |||
| /** | |||
| * 商品算价结果 | |||
| */ | |||
| @SerializedName(value = "order_discount_detail") | |||
| private OrderDiscountDetail order_discount_detail; | |||
| /** | |||
| * 商品算价结果 | |||
| */ | |||
| @SerializedName(value = "item_discount_detail") | |||
| private List<ItemDiscountDetail> item_discount_detail; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class GoodsDiscountDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 商品id,此处为课程id,注意这里是string类型 | |||
| */ | |||
| @SerializedName(value = "goods_id") | |||
| private String goodsId; | |||
| /** | |||
| * 是 | |||
| * 购买数量 | |||
| */ | |||
| @SerializedName(value = "quantity") | |||
| private Integer quantity; | |||
| /** | |||
| * 是 | |||
| * 商品总价,单位:分 | |||
| */ | |||
| @SerializedName(value = "total_amount") | |||
| private Integer totalAmount; | |||
| /** | |||
| * 是 | |||
| * 该商品总优惠金额,该商品的实付金额=total_amount-discount_amount | |||
| */ | |||
| @SerializedName(value = "discountAmount") | |||
| private Integer discountAmount; | |||
| /** | |||
| * 营销明细 | |||
| */ | |||
| @SerializedName(value = "marketing_detail") | |||
| private List<MarketingDetail> marketingDetail; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class OrderDiscountDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 订单维度总优惠金额,单位: 分 | |||
| */ | |||
| @SerializedName(value = "order_total_discount_amount") | |||
| private Integer orderTotalDiscountAmount; | |||
| /** | |||
| * 是 | |||
| * 商品(sku)维度总优惠金额,单位: 分 | |||
| */ | |||
| @SerializedName(value = "goods_total_discount_amount") | |||
| private Integer goodsTotalDiscountAmount; | |||
| /** | |||
| * 营销明细 | |||
| */ | |||
| @SerializedName(value = "marketing_detail") | |||
| private List<MarketingDetail> marketingDetail; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class ItemDiscountDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 商品id,此处为课程id,注意这里是string类型 | |||
| */ | |||
| @SerializedName(value = "goods_id") | |||
| private String goodsId; | |||
| /** | |||
| * 是 | |||
| * 商品总价,单位:分 | |||
| */ | |||
| @SerializedName(value = "total_amount") | |||
| private Integer totalAmount; | |||
| /** | |||
| * 是 | |||
| * 该商品总优惠金额,该商品的实付金额=total_amount-discount_amount | |||
| */ | |||
| @SerializedName(value = "discountAmount") | |||
| private Integer discountAmount; | |||
| /** | |||
| * 营销明细 | |||
| */ | |||
| @SerializedName(value = "marketing_detail") | |||
| private List<MarketingDetail> marketingDetail; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class MarketingDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 营销id(用户身份id,优惠券id,积分id或者活动id) | |||
| */ | |||
| @SerializedName(value = "id") | |||
| private String id; | |||
| /** | |||
| * 是 | |||
| * | |||
| * 营销类型: | |||
| * 1: 用户身份 | |||
| * 2: 优惠券 | |||
| * 3: 积分(暂不开放) | |||
| * 4: 活动 | |||
| */ | |||
| @SerializedName(value = "type") | |||
| private Integer type; | |||
| /** | |||
| * 是 | |||
| * 该营销策略优惠金额,单位: 分 | |||
| */ | |||
| @SerializedName(value = "discountAmount") | |||
| private Integer discountAmount; | |||
| /** | |||
| * 营销名称 | |||
| */ | |||
| @SerializedName(value = "title") | |||
| private String title; | |||
| /** | |||
| * 营销备注 | |||
| */ | |||
| @SerializedName(value = "note") | |||
| private String note; | |||
| /** | |||
| * 优惠范围 | |||
| */ | |||
| @SerializedName(value = "discount_range") | |||
| private Integer discountRange; | |||
| /** | |||
| * 营销子类型 | |||
| */ | |||
| @SerializedName(value = "subtype") | |||
| private String subtype; | |||
| /** | |||
| * 不同type含义不同,若type=3,value则为积分值 | |||
| */ | |||
| @SerializedName(value = "value") | |||
| private Integer value; | |||
| } | |||
| } | |||
| @@ -0,0 +1,64 @@ | |||
| package com.iformall.douyin.payv2.request; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 订单推送核销状态请求对象 | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtRefundAuditMsgRequest implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 开发者侧退款单号 | |||
| */ | |||
| @SerializedName(value = "out_refund_no") | |||
| private String outRefundNo; | |||
| /** | |||
| * 审核状态,1-同意退款 2-不同意退款 | |||
| */ | |||
| @SerializedName(value = "refund_audit_status") | |||
| private Integer refundAuditStatus; | |||
| /** | |||
| * 不同意退款信息(不同意退款时必填),长度 <= 512 byte | |||
| */ | |||
| @SerializedName(value = "deny_message") | |||
| private String denyMessage; | |||
| /** | |||
| * 核销的商铺poi信息,详细结构见下表,最多1024个字节。 | |||
| * shop_name string poi商品必填 | |||
| * 核销店铺名称,参考商铺同步接口中的店铺名称(name) | |||
| * ext_valid_shop_id string poi商品必填 | |||
| * 核销门店的外部店铺id,参考商铺同步接口中的接入方店铺id(supplier_ext_id) | |||
| * valid_poi_id_str string poi商品必填 | |||
| * 核销门店对应的抖音poi_id,参考商铺同步接口中的抖音poi id(poi_id) | |||
| */ | |||
| @SerializedName(value = "poi_info") | |||
| private Boolean poiInfo; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class ItemOrder implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| } | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import java.io.Serializable; | |||
| /** | |||
| * <pre> | |||
| * 结果共用属性类. | |||
| * Created by Binary Wang on 2016-10-24. | |||
| * </pre> | |||
| * | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class BaseTtPayResult<T> implements Serializable { | |||
| /** | |||
| * 返回状态码. | |||
| */ | |||
| @SerializedName("err_no") | |||
| protected Integer errNo; | |||
| public boolean isSuccess() { | |||
| return errNo.intValue() == 0; | |||
| } | |||
| /** | |||
| * 返回信息. | |||
| */ | |||
| @SerializedName("err_tips") | |||
| protected String errTips; | |||
| @SerializedName("data") | |||
| private T data; | |||
| /** | |||
| * Gets logger. | |||
| * | |||
| * @return the logger | |||
| */ | |||
| protected Logger getLogger() { | |||
| return LoggerFactory.getLogger(this.getClass()); | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return WxGsonBuilder.create().toJson(this); | |||
| } | |||
| } | |||
| @@ -0,0 +1,226 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import cn.binarywang.wx.miniapp.bean.WxMaGetLiveInfo; | |||
| 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 CreateOrderCallback implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 是 | |||
| * 抖音开平侧生成的订单号 | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| private String orderId; | |||
| /** | |||
| * 是 | |||
| * 商品信息,详情见 goods参数 部分 | |||
| */ | |||
| @SerializedName(value = "goods") | |||
| private List<Good> goods; | |||
| /** | |||
| * 是 | |||
| * 订单总价格,单位[分] | |||
| * 用户实付金额=total_amount-discount | |||
| */ | |||
| @SerializedName(value = "total_amount") | |||
| private Integer totalAmount; | |||
| /** | |||
| * 是 | |||
| * 订单折扣,单位[分] | |||
| */ | |||
| @SerializedName(value = "discount") | |||
| private Integer discount; | |||
| /** | |||
| * 否 | |||
| * 预下单时开发者定义的透传信息 | |||
| */ | |||
| @SerializedName(value = "cp_extra") | |||
| private String cpExtra; | |||
| /** | |||
| * 是 | |||
| * 订单创建时间,13位时间戳,毫秒 | |||
| */ | |||
| @SerializedName(value = "create_order_time") | |||
| private Long createOrderTime; | |||
| /** | |||
| * 是 | |||
| * 用户OpenID | |||
| */ | |||
| @SerializedName(value = "open_id") | |||
| private String openId; | |||
| /** | |||
| * 否 | |||
| * 用户手机号 | |||
| */ | |||
| @SerializedName(value = "phone_num") | |||
| private String phoneNum; | |||
| /** | |||
| * 否 | |||
| * 联系人姓名 | |||
| */ | |||
| @SerializedName(value = "contact_name") | |||
| private String contactName; | |||
| /** | |||
| * 是 | |||
| * 小程序id | |||
| */ | |||
| @SerializedName(value = "app_id") | |||
| private String appId; | |||
| /** | |||
| * 否 | |||
| * 用户的 UnionID | |||
| */ | |||
| @SerializedName(value = "union_id") | |||
| private String unionId; | |||
| /** | |||
| * 是 | |||
| * 核销类型,开平告知此订单是否可走闭环核销判断结果。 | |||
| * 0-非闭环核销,开发者自行处理券码生成及展示,通过push_delivery接口推送核销状态,1-闭环核销,开平负责生券,开发者使用核销组件展示,使用验券准备和验券接口核销。 | |||
| */ | |||
| @SerializedName(value = "delivery_type") | |||
| private Integer deliveryType; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class Good implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 商品图片链接 | |||
| */ | |||
| @SerializedName(value = "img_url") | |||
| private String imgUrl; | |||
| /** | |||
| * 是 | |||
| * 商品标题 | |||
| */ | |||
| @SerializedName(value = "title") | |||
| private String title; | |||
| /** | |||
| * 是 | |||
| * 商品副标题 | |||
| */ | |||
| @SerializedName(value = "sub_title") | |||
| private String subTitle; | |||
| /** | |||
| * 是 | |||
| * | |||
| * 商品标签,对应poi多门店SPU同步的sub_title,例如:随时退|免预约|提前3日预约 (“|”是中文类型) | |||
| */ | |||
| @SerializedName(value = "labels") | |||
| private String labels; | |||
| /** | |||
| * 是 | |||
| * 券的可用时间(目前仅用于展示),例如:“周一至周五可用”、“非节假日可用” | |||
| */ | |||
| @SerializedName(value = "date_rule") | |||
| private String dateRule; | |||
| /** | |||
| * 是 | |||
| * 商品原价,单位[分] | |||
| */ | |||
| @SerializedName(value = "origin_price") | |||
| private Integer originPrice; | |||
| /** | |||
| * 是 | |||
| * 商品去掉折扣后的单价,单位[分] | |||
| */ | |||
| @SerializedName(value = "price") | |||
| private Integer price; | |||
| /** | |||
| * 是 | |||
| * 购买的商品数量 | |||
| */ | |||
| @SerializedName(value = "quantity") | |||
| private Integer quantity; | |||
| /** | |||
| * 否 | |||
| * 对应门店的Poi ID | |||
| */ | |||
| @SerializedName(value = "poi_id") | |||
| private String poiId; | |||
| /** | |||
| * 是 | |||
| * 商品id | |||
| */ | |||
| @SerializedName(value = "goods_id") | |||
| private String goodsId; | |||
| /** | |||
| * 是 | |||
| * item_order_id列表,id个数与quantity一致 | |||
| */ | |||
| @SerializedName(value = "item_order_id_list") | |||
| private List<String> itemOrderIdList; | |||
| /** | |||
| * 是 | |||
| * 商品id类别,1:poi商品,2:非poi商品 | |||
| */ | |||
| @SerializedName(value = "goods_id_type") | |||
| private Integer goodsIdType; | |||
| /** | |||
| * 是 | |||
| * 商品item_order信息,详情见 item_order_info_list部分 | |||
| */ | |||
| @SerializedName(value = "item_order_info") | |||
| protected List<ItemOrderInfo> 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; | |||
| } | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class OriginNotifyResponse implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @SerializedName(value = "msg") | |||
| private String msg; | |||
| /** | |||
| * 枚举值: | |||
| * pre_create_order 预下单回调 | |||
| * pre_create_refund 退款审核回调 | |||
| */ | |||
| @SerializedName(value = "type") | |||
| private String type; | |||
| /** | |||
| * 固定值:"2.0" callback版本,用于开发者识别回调参数的变更 | |||
| */ | |||
| @SerializedName(value = "version") | |||
| private String version; | |||
| } | |||
| @@ -0,0 +1,112 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * 请求分账API返回的分账结果实体 | |||
| * | |||
| * @author pg | |||
| * @date 2021-6-24 | |||
| */ | |||
| @Data | |||
| public class ProfitSharingResult implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 返回状态码. | |||
| */ | |||
| @SerializedName("err_no") | |||
| protected Integer errNo; | |||
| public boolean isSuccess() { | |||
| return errNo.intValue() == 0; | |||
| } | |||
| /** | |||
| * 返回信息. | |||
| */ | |||
| @SerializedName("err_tips") | |||
| protected String errTips; | |||
| /** | |||
| * 订单的分账结果 | |||
| */ | |||
| @SerializedName("data") | |||
| private List<Receiver> data; | |||
| @Data | |||
| public static class Receiver implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 开发者交易订单id,长度<=64byte,数字、ASCII字符组成 | |||
| */ | |||
| @SerializedName("out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * 开发者分账单id,长度<=64byte,数字、ASCII字符组成 | |||
| */ | |||
| @SerializedName("out_settle_no") | |||
| private String outSettleNo; | |||
| /** | |||
| * 小程序侧交易订单id,长度<=64byte,数字、ASCII字符组成 | |||
| */ | |||
| @SerializedName("order_id") | |||
| private String orderId; | |||
| /** | |||
| * 小程序侧分账单id,长度<=64byte,数字、ASCII字符组成 | |||
| */ | |||
| @SerializedName("settle_id") | |||
| private String settleId; | |||
| /** | |||
| * 分账金额,单位[分] | |||
| */ | |||
| @SerializedName("settle_amount") | |||
| private Integer settleAmount; | |||
| /** | |||
| * 分账状态:INIT,PROCESSING,SUCCESS,FAIL | |||
| */ | |||
| @SerializedName("settle_status") | |||
| private String settleStatus; | |||
| /** | |||
| * 分账详情,如“商户号ABC-分成金额(分)100” | |||
| */ | |||
| @SerializedName("settle_detail") | |||
| private String settleDetail; | |||
| /** | |||
| * 分账时间,13位时间戳,毫秒 | |||
| */ | |||
| @SerializedName("settle_time") | |||
| private Long settleTime; | |||
| /** | |||
| * 手续费,单位[分] | |||
| */ | |||
| @SerializedName("rake") | |||
| private Integer rake; | |||
| /** | |||
| * 佣金,单位[分] | |||
| */ | |||
| @SerializedName("commission") | |||
| private Integer commission; | |||
| /** | |||
| * 透传字段,开发者自定义,<=2048字节,不支持二进制数据 | |||
| */ | |||
| @SerializedName("cp_extra") | |||
| private String cpExtra; | |||
| } | |||
| } | |||
| @@ -0,0 +1,138 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * 结果通知. | |||
| * | |||
| * @author | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class RefundOrderCallback implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 小程序的appid | |||
| */ | |||
| @SerializedName(value = "app_id") | |||
| private String appId; | |||
| /** | |||
| * 用户openid | |||
| */ | |||
| @SerializedName(value = "open_id") | |||
| private String openId; | |||
| /** | |||
| * 抖音开平侧退款单号 | |||
| */ | |||
| @SerializedName(value = "refund_id") | |||
| private String refundId; | |||
| /** | |||
| * 抖音开平侧订单号 | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| private String orderId; | |||
| /** | |||
| * 开发者侧订单号 | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * 退款总金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "refund_total_amount") | |||
| private Integer refundTotalAmount; | |||
| /** | |||
| * 退款审核的最后期限,超过该期限无需商家审核,自动退款,13位时间戳,毫秒 | |||
| */ | |||
| @SerializedName(value = "refund_audit_deadline") | |||
| private Long refundAuditDeadline; | |||
| /** | |||
| * 退款创建时间,13位时间戳,毫秒 | |||
| */ | |||
| @SerializedName(value = "create_refund_time") | |||
| private Long createRefundTime; | |||
| /** | |||
| * 退款来源:1-用户发起退款 3-过期自动退 | |||
| */ | |||
| @SerializedName(value = "refund_source") | |||
| private Integer refundSource; | |||
| /** | |||
| * cp 自定义字段,不支持二进制,长度 <= 2048byte | |||
| */ | |||
| @SerializedName(value = "cp_extra") | |||
| private String cpExtra; | |||
| /** | |||
| * 退款原因,退款原因有多个 | |||
| */ | |||
| @SerializedName(value = "refund_reason") | |||
| private List<String> refundReason; | |||
| /** | |||
| *退款补充说明 | |||
| */ | |||
| @SerializedName(value = "refund_description") | |||
| private String refundDescription; | |||
| /** | |||
| * 退款商品单信息 (新系统订单退款必填) | |||
| */ | |||
| @SerializedName(value = "refund_item_detail") | |||
| private RefundItemDetail refundItemDetail; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class RefundItemDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 用户需要退款多少个商品单 | |||
| */ | |||
| @SerializedName(value = "item_order_quantity") | |||
| private Integer itemOrderQuantity; | |||
| /** | |||
| * 本次退款的商品单列表 | |||
| */ | |||
| @SerializedName(value = "item_order_detail") | |||
| private List<ItemOrderDetail> itemOrderDetail; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class ItemOrderDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 用户需要退款多少个商品单 | |||
| */ | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| /** | |||
| * 用户需要退款多少个商品单 | |||
| */ | |||
| @SerializedName(value = "refund_amount") | |||
| private Integer refundAmount; | |||
| } | |||
| } | |||
| @@ -0,0 +1,304 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 查询CPS订单 返回结果对象 | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class TtPayCpsOrderQueryV2Result implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 抖音开平侧订单号 | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| private String orderId; | |||
| /** | |||
| * 开发者侧订单号,与order_id一一对应 | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| *cps订单支付相关信息 | |||
| */ | |||
| @SerializedName(value = "payment_info") | |||
| private PaymentInfo paymentInfo; | |||
| /** | |||
| *cps相关信息 | |||
| */ | |||
| @SerializedName(value = "cps_info") | |||
| private CpsInfo cpsInfo; | |||
| /** | |||
| *cps订单已退款记录信息 | |||
| * - refund_info字段结构(只展示已退款记录,退款失败和退款中不展示) | |||
| */ | |||
| @SerializedName(value = "refund_info") | |||
| private RefundInfo refundInfo; | |||
| /** | |||
| *cps订单已核销记录信息 | |||
| * - delivery_info字段结构(只展示已核销记录) | |||
| */ | |||
| @SerializedName(value = "delivery_info") | |||
| private DeliveryInfo deliveryInfo; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class PaymentInfo implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 订单实际支付金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "total_fee") | |||
| private Integer totalFee; | |||
| /** | |||
| * 订单状态, | |||
| * INIT 初始状态 | |||
| * PROCESS 订单处理中 | |||
| * SUCCESS:成功 | |||
| * FAIL:失败 | |||
| * TIMEOUT:用户超时未支付 | |||
| */ | |||
| @SerializedName(value = "order_status") | |||
| private String orderStatus; | |||
| /** | |||
| * 支付时间,格式:2021-12-12 00:00:00 | |||
| */ | |||
| @SerializedName(value = "pay_time") | |||
| private String payTime; | |||
| /** | |||
| * 支付渠道枚举,1:微信,2:支付宝 | |||
| */ | |||
| @SerializedName(value = "pay_channel") | |||
| private Integer payChannel; | |||
| /** | |||
| * 渠道支付单号,如微信的支付单号 | |||
| */ | |||
| @SerializedName(value = "channel_pay_id") | |||
| private String channelPayId; | |||
| /** | |||
| * 卖家商户号id | |||
| */ | |||
| @SerializedName(value = "seller_uid") | |||
| private String sellerUid; | |||
| /** | |||
| * 预下单时开发者定义的透传信息 | |||
| */ | |||
| @SerializedName(value = "cp_extra") | |||
| private String cpExtra; | |||
| /** | |||
| * 结果描述信息,如失败原因 | |||
| */ | |||
| @SerializedName(value = "message") | |||
| private String message; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class CpsInfo implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 订单总佣金,单位分 | |||
| */ | |||
| @SerializedName(value = "total_commission_amount") | |||
| private Integer totalCommissionAmount; | |||
| /** | |||
| * 订单状态, | |||
| * INIT 初始状态 | |||
| * PROCESS 订单处理中 | |||
| * SUCCESS:成功 | |||
| * FAIL:失败 | |||
| * TIMEOUT:用户超时未支付 | |||
| */ | |||
| @SerializedName(value = "cps_item_list") | |||
| private List<CpsItem> cps_item_list; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class CpsItem implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 分佣比例,万分位 | |||
| */ | |||
| @SerializedName(value = "commission_rate") | |||
| private Integer commissionRate; | |||
| /** | |||
| * 分佣用户ID | |||
| */ | |||
| @SerializedName(value = "commission_user_id") | |||
| private Long commissionUserId; | |||
| /** | |||
| * 佣金,单位分 | |||
| */ | |||
| @SerializedName(value = "commission_amount") | |||
| private Integer commissionAmount; | |||
| /** | |||
| * 分佣类型,1 短视频, 2 直播间 | |||
| */ | |||
| @SerializedName(value = "source_type") | |||
| private Integer sourceType; | |||
| /** | |||
| * 短视频/直播间ID | |||
| */ | |||
| @SerializedName(value = "item_id") | |||
| private Long itemId; | |||
| /** | |||
| * 售价,单位分 | |||
| */ | |||
| @SerializedName(value = "sell_amount") | |||
| private Integer sellAmount; | |||
| /** | |||
| * cps订单状态,交易系统2.0为子单状态 | |||
| * 0-未支付, | |||
| * 1-已支付(待使用); | |||
| * 2-已退款(不分佣); | |||
| * 3-已核销(已分佣) | |||
| */ | |||
| @SerializedName(value = "status") | |||
| private Integer status; | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class RefundInfo implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 订单退款总金额,单位分,没有已退款记录,为0 | |||
| */ | |||
| @SerializedName(value = "total_refund_amount") | |||
| private Integer total_refund_amount; | |||
| /** | |||
| * 分佣用户ID | |||
| */ | |||
| @SerializedName(value = "refund_items") | |||
| private List<RefundItem> refund_items; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class RefundItem implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 开发者系统生成的退款单号,与抖音开平退款单号refund_id 唯一关联 | |||
| */ | |||
| @SerializedName(value = "out_refund_no") | |||
| private String outRefundNo; | |||
| /** | |||
| * 退款金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "refund_amount") | |||
| private Integer refundAmount; | |||
| /** | |||
| * 显示退款状态,默认“已退款” | |||
| */ | |||
| @SerializedName(value = "refundStatus") | |||
| private String refundStatus; | |||
| /** | |||
| * 退款时间,13位毫秒时间戳,只有已退款才有退款时间 | |||
| */ | |||
| @SerializedName(value = "refunded_at") | |||
| private Long refunded_at; | |||
| /** | |||
| * 抖音开平侧的商品单号,只存在交易2.0系统 | |||
| */ | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class DeliveryInfo implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 订单核销总金额,单位分,没有核销记录,为0 | |||
| */ | |||
| @SerializedName(value = "total_delivery_amount") | |||
| private Integer totalDeliveryAmount; | |||
| /** | |||
| * 分佣用户ID | |||
| */ | |||
| @SerializedName(value = "delivery_items") | |||
| private List<DeliveryItem> deliveryItems; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class DeliveryItem implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 核销金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "delivery_amount") | |||
| private Integer deliveryAmount; | |||
| /** | |||
| * 显示核销状态,默认“已核销” | |||
| */ | |||
| @SerializedName(value = "delivery_status") | |||
| private String deliveryStatus; | |||
| /** | |||
| * 退款时间,13位毫秒时间戳,只有已退款才有退款时间 | |||
| */ | |||
| @SerializedName(value = "delivery_at") | |||
| private Long deliveryAt; | |||
| /** | |||
| * 抖音开平侧的商品单号,只存在交易2.0系统 | |||
| */ | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| } | |||
| } | |||
| @@ -0,0 +1,119 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import io.swagger.models.auth.In; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 查询订单 返回结果对象 | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class TtPayOrderQueryV2Result implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 抖音开平侧订单号 | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| private String orderId; | |||
| /** | |||
| * 开发者侧订单号,与order_id一一对应 | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| private String outOrderNo; | |||
| /** | |||
| * 已退款金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "refund_amount") | |||
| private Integer refundAmount; | |||
| /** | |||
| * 已分账金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "settle_amount") | |||
| private Integer settleAmount; | |||
| /** | |||
| * 订单实际支付金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "total_fee") | |||
| private Integer totalFee; | |||
| /** | |||
| * 订单状态, | |||
| * INIT 初始状态 | |||
| * PROCESS 订单处理中 | |||
| * SUCCESS:成功 | |||
| * FAIL:失败 | |||
| * TIMEOUT:用户超时未支付 | |||
| */ | |||
| @SerializedName(value = "order_status") | |||
| private String orderStatus; | |||
| /** | |||
| * 支付时间,格式:2021-12-12 00:00:00 | |||
| */ | |||
| @SerializedName(value = "pay_time") | |||
| private String payTime; | |||
| /** | |||
| * 支付渠道枚举,1:微信,2:支付宝 | |||
| */ | |||
| @SerializedName(value = "pay_channel") | |||
| private Integer payChannel; | |||
| /** | |||
| * 渠道支付单号,如微信的支付单号 | |||
| */ | |||
| @SerializedName(value = "channel_pay_id") | |||
| private String channelPayId; | |||
| /** | |||
| * 卖家商户号id | |||
| */ | |||
| @SerializedName(value = "seller_uid") | |||
| private String sellerUid; | |||
| /** | |||
| * 视频id | |||
| */ | |||
| @SerializedName(value = "item_id") | |||
| private String itemId; | |||
| /** | |||
| * 预下单时开发者定义的透传信息 | |||
| */ | |||
| @SerializedName(value = "cp_extra") | |||
| private String cpExtra; | |||
| /** | |||
| * 结果描述信息,如失败原因 | |||
| */ | |||
| @SerializedName(value = "message") | |||
| private String message; | |||
| /** | |||
| * 担保支付单id | |||
| */ | |||
| @SerializedName(value = "payment_order_id") | |||
| private String paymentOrderId; | |||
| /** | |||
| * 订单核销类型: | |||
| * 0-非闭环核销,开发者自行处理券码生成及展示,通过push_delivery接口推送核销状态。 | |||
| * 1-闭环核销,开平负责生券,开发者使用核销组件展示,使用验券准备和验券接口核销。 | |||
| */ | |||
| @SerializedName(value = "delivery_type") | |||
| private Integer deliveryType; | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 退款返回结果. | |||
| * </pre> | |||
| * | |||
| * @author | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class TtPayRefundQueryV2Result implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 系统退款单号,开放平台生成的退款单号 | |||
| */ | |||
| @SerializedName(value = "refund_id") | |||
| private String refundId; | |||
| /** | |||
| * 开发者系统生成的退款单号,与抖音开平退款单号refund_id 唯一关联 | |||
| */ | |||
| @SerializedName(value = "out_refund_no") | |||
| private String outRefundNo; | |||
| /** | |||
| * 退款金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "refund_total_amount") | |||
| private Integer refundTotalAmount; | |||
| /** | |||
| * 退款状态 | |||
| * 退款中- PROCESSING,已退款- SUCCESS,退款失败- FAIL | |||
| */ | |||
| @SerializedName(value = "refund_status") | |||
| private String refundStatus; | |||
| /** | |||
| * 退款时间,13位毫秒时间戳,只有已退款才有退款时间 | |||
| */ | |||
| @SerializedName(value = "refund_at") | |||
| private Long refundAt; | |||
| /** | |||
| * 退款结果信息,非商家拒绝退款导致的退款失败,可以通过该字段了解退款失败原因 | |||
| */ | |||
| @SerializedName(value = "message") | |||
| private String message; | |||
| /** | |||
| * 系统订单信息,开放平台生成的订单号 | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| private String orderId; | |||
| /** | |||
| * 商品单信息 (新系统订单退款才有的信息) | |||
| */ | |||
| @SerializedName(value = "item_order_detail") | |||
| private List<itemOrderDetail> itemOrderDetail; | |||
| /** | |||
| * 退款审核信息(在新系统发起的退款单才有) | |||
| */ | |||
| @SerializedName(value = "merchant_audit_detail") | |||
| private MerchantAuditDetail merchantAuditDetail; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class itemOrderDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 抖音开平侧的商品单号 | |||
| */ | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| /** | |||
| * 该商品单退款金额,单位[分] | |||
| */ | |||
| @SerializedName(value = "refund_amount") | |||
| private Integer refundAmount; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class MerchantAuditDetail implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 退款审核的最后期限,过期无需审核,自动退款,13位unix时间戳,精度:毫秒 | |||
| */ | |||
| @SerializedName(value = "refund_audit_deadline") | |||
| private Long refundAuditDeadline; | |||
| /** | |||
| * 退款审核状态 | |||
| * INIT-初始化 TOAUDIT-待审核 AGREE-同意 DENY-拒绝 OVERTIME-超时未审核自动同意 | |||
| */ | |||
| @SerializedName(value = "audit_status") | |||
| private String auditStatus; | |||
| /** | |||
| * 不同意退款信息(不同意退款时必填),长度 <= 512 byte | |||
| */ | |||
| @SerializedName(value = "deny_message") | |||
| private String denyMessage; | |||
| } | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| /** | |||
| * <pre> | |||
| * 申请退款返回结果. | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class TtPayRefundV2Result implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * 抖音开放平台交易系统内部退款单号 | |||
| */ | |||
| @SerializedName(value = "refund_id") | |||
| private String refundId; | |||
| /** | |||
| * 退款审核的最后期限,过期无需审核,自动退款,13位unix时间戳,精度:毫秒 | |||
| */ | |||
| @SerializedName(value = "refund_audit_deadline") | |||
| private Long refundAuditDeadline; | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| package com.iformall.douyin.payv2.result; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import lombok.experimental.Accessors; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| /** | |||
| * <pre> | |||
| * 统一下单请求参数对象. | |||
| * </pre> | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| @Accessors(chain = true) | |||
| public class TtPayUnifiedOrderV2Result implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| * 是 | |||
| * 抖音开平侧生成的订单号 | |||
| */ | |||
| @SerializedName(value = "order_id") | |||
| protected String orderId; | |||
| /** | |||
| * 是 | |||
| * 开发者系统生成的订单号 | |||
| */ | |||
| @SerializedName(value = "out_order_no") | |||
| protected String outOrderNo; | |||
| /** | |||
| * 是 | |||
| * 吊起收银台的支付订单号 | |||
| */ | |||
| @SerializedName(value = "pay_order_id") | |||
| protected String payOrderId; | |||
| /** | |||
| * 是 | |||
| * 吊起收银台的token | |||
| */ | |||
| @SerializedName(value = "pay_order_token") | |||
| protected String payOrderToken; | |||
| /** | |||
| * 是 | |||
| * 商品item_order信息,详情见 item_order_info_list部分 | |||
| */ | |||
| @SerializedName(value = "item_order_info_list") | |||
| protected List<ItemOrderInfo> itemOrderInfoList; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class ItemOrderInfo implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @SerializedName(value = "goods_id") | |||
| private String goodsId; | |||
| /** | |||
| * 是 | |||
| * item_order_id列表,id个数与下单时对应goods_id的quantity一致 | |||
| */ | |||
| @SerializedName(value = "item_order_id_list") | |||
| private List<String> itemOrderIdList; | |||
| /** | |||
| * 是 | |||
| * 商品item_order详细信息,详情见 item_order_detail部分 | |||
| */ | |||
| @SerializedName(value = "item_order_detail") | |||
| private List<String> itemOrderDetail; | |||
| } | |||
| @Data | |||
| @NoArgsConstructor | |||
| public static class ItemOrderDetail implements Serializable { | |||
| private static final long serialVersionUID = -1L; | |||
| /** | |||
| * item单id | |||
| */ | |||
| @SerializedName(value = "item_order_id") | |||
| private String itemOrderId; | |||
| /** | |||
| * 商品优惠后价格 | |||
| */ | |||
| @SerializedName(value = "price") | |||
| private Integer price; | |||
| } | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| package com.iformall.douyin.payv2.util; | |||
| import org.apache.http.client.methods.HttpRequestWrapper; | |||
| import java.io.IOException; | |||
| public interface Credentials { | |||
| String getSchema(); | |||
| String getToken(HttpRequestWrapper request) throws IOException; | |||
| } | |||
| @@ -0,0 +1,89 @@ | |||
| package com.iformall.douyin.payv2.util; | |||
| import me.chanjar.weixin.common.error.WxRuntimeException; | |||
| import sun.misc.BASE64Decoder; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.security.KeyFactory; | |||
| import java.security.NoSuchAlgorithmException; | |||
| import java.security.PrivateKey; | |||
| import java.security.PublicKey; | |||
| import java.security.cert.*; | |||
| import java.security.spec.InvalidKeySpecException; | |||
| import java.security.spec.PKCS8EncodedKeySpec; | |||
| import java.security.spec.X509EncodedKeySpec; | |||
| import java.util.Base64; | |||
| public class PemUtils { | |||
| public static PrivateKey loadPrivateKey(InputStream inputStream) { | |||
| try { | |||
| ByteArrayOutputStream array = new ByteArrayOutputStream(); | |||
| byte[] buffer = new byte[1024]; | |||
| int length; | |||
| while ((length = inputStream.read(buffer)) != -1) { | |||
| array.write(buffer, 0, length); | |||
| } | |||
| String privateKey = array.toString("utf-8") | |||
| .replace("-----BEGIN PRIVATE KEY-----", "") | |||
| .replace("-----END PRIVATE KEY-----", "") | |||
| .replaceAll("\\s+", ""); | |||
| KeyFactory kf = KeyFactory.getInstance("RSA"); | |||
| return kf.generatePrivate( | |||
| new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))); | |||
| } catch (NoSuchAlgorithmException e) { | |||
| throw new WxRuntimeException("当前Java环境不支持RSA", e); | |||
| } catch (InvalidKeySpecException e) { | |||
| throw new WxRuntimeException("无效的密钥格式"); | |||
| } catch (IOException e) { | |||
| throw new WxRuntimeException("无效的密钥"); | |||
| } | |||
| } | |||
| public static X509Certificate loadCertificate(InputStream inputStream) { | |||
| try { | |||
| CertificateFactory cf = CertificateFactory.getInstance("X509"); | |||
| X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); | |||
| cert.checkValidity(); | |||
| return cert; | |||
| } catch (CertificateExpiredException e) { | |||
| throw new WxRuntimeException("证书已过期", e); | |||
| } catch (CertificateNotYetValidException e) { | |||
| throw new WxRuntimeException("证书尚未生效", e); | |||
| } catch (CertificateException e) { | |||
| throw new WxRuntimeException("无效的证书", e); | |||
| } | |||
| } | |||
| public static PublicKey loadPublicKey(InputStream inputStream) { | |||
| try { | |||
| ByteArrayOutputStream array = new ByteArrayOutputStream(); | |||
| byte[] buffer = new byte[1024]; | |||
| int length; | |||
| while ((length = inputStream.read(buffer)) != -1) { | |||
| array.write(buffer, 0, length); | |||
| } | |||
| String publicKey = array.toString("utf-8") | |||
| .replace("-----BEGIN PUBLIC KEY-----", "") | |||
| .replace("-----END PUBLIC KEY-----", "") | |||
| .replaceAll("\\s+", ""); | |||
| KeyFactory kf = KeyFactory.getInstance("RSA"); | |||
| return kf.generatePublic( | |||
| new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(publicKey))); | |||
| } catch (NoSuchAlgorithmException e) { | |||
| throw new WxRuntimeException("当前Java环境不支持RSA", e); | |||
| } catch (InvalidKeySpecException e) { | |||
| throw new WxRuntimeException("无效的密钥格式"); | |||
| } catch (IOException e) { | |||
| throw new WxRuntimeException("无效的密钥"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,81 @@ | |||
| package com.iformall.douyin.payv2.util; | |||
| import org.apache.http.HttpEntity; | |||
| import org.apache.http.HttpEntityEnclosingRequest; | |||
| import org.apache.http.HttpException; | |||
| import org.apache.http.StatusLine; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpExecutionAware; | |||
| import org.apache.http.client.methods.HttpRequestWrapper; | |||
| import org.apache.http.client.protocol.HttpClientContext; | |||
| import org.apache.http.conn.routing.HttpRoute; | |||
| import org.apache.http.entity.BufferedHttpEntity; | |||
| import org.apache.http.entity.ByteArrayEntity; | |||
| import org.apache.http.impl.execchain.ClientExecChain; | |||
| import org.apache.http.util.EntityUtils; | |||
| import java.io.IOException; | |||
| public class SignatureExec implements ClientExecChain { | |||
| final ClientExecChain mainExec; | |||
| final Credentials credentials; | |||
| final Validator validator; | |||
| SignatureExec(Credentials credentials, Validator validator, ClientExecChain mainExec) { | |||
| this.credentials = credentials; | |||
| this.validator = validator; | |||
| this.mainExec = mainExec; | |||
| } | |||
| protected HttpEntity newRepeatableEntity(HttpEntity entity) throws IOException { | |||
| byte[] content = EntityUtils.toByteArray(entity); | |||
| ByteArrayEntity newEntity = new ByteArrayEntity(content); | |||
| newEntity.setContentEncoding(entity.getContentEncoding()); | |||
| newEntity.setContentType(entity.getContentType()); | |||
| return newEntity; | |||
| } | |||
| protected void convertToRepeatableResponseEntity(CloseableHttpResponse response) throws IOException { | |||
| HttpEntity entity = response.getEntity(); | |||
| if (entity != null && !entity.isRepeatable()) { | |||
| response.setEntity(newRepeatableEntity(entity)); | |||
| } | |||
| } | |||
| protected void convertToRepeatableRequestEntity(HttpRequestWrapper request) throws IOException { | |||
| if (request instanceof HttpEntityEnclosingRequest) { | |||
| HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); | |||
| if (entity != null) { | |||
| ((HttpEntityEnclosingRequest) request).setEntity(new BufferedHttpEntity(entity)); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public CloseableHttpResponse execute(HttpRoute route, HttpRequestWrapper request, | |||
| HttpClientContext context, HttpExecutionAware execAware) throws IOException, HttpException { | |||
| return executeWithSignature(route, request, context, execAware); | |||
| } | |||
| private CloseableHttpResponse executeWithSignature(HttpRoute route, HttpRequestWrapper request, | |||
| HttpClientContext context, HttpExecutionAware execAware) throws IOException, HttpException { | |||
| // 添加认证信息 | |||
| request.addHeader("Byte-Authorization", | |||
| credentials.getSchema() + " " + credentials.getToken(request)); | |||
| // 执行 | |||
| CloseableHttpResponse response = mainExec.execute(route, request, context, execAware); | |||
| // 对成功应答验签 | |||
| StatusLine statusLine = response.getStatusLine(); | |||
| if (statusLine.getStatusCode() >= 200 && statusLine.getStatusCode() < 300) { | |||
| convertToRepeatableResponseEntity(response); | |||
| if (!validator.validate(response)) { | |||
| throw new HttpException("应答的支付签名验证失败"); | |||
| } | |||
| } | |||
| return response; | |||
| } | |||
| } | |||
| @@ -0,0 +1,70 @@ | |||
| package com.iformall.douyin.payv2.util; | |||
| import com.iformall.douyin.payv2.auth.*; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import org.apache.http.impl.client.HttpClientBuilder; | |||
| import org.apache.http.impl.execchain.ClientExecChain; | |||
| import java.security.PrivateKey; | |||
| import java.security.PublicKey; | |||
| public class TtPayV2HttpClientBuilder extends HttpClientBuilder { | |||
| private Credentials credentials; | |||
| private Validator validator; | |||
| static final String OS = System.getProperty("os.name") + "/" + System.getProperty("os.version"); | |||
| static final String VERSION = System.getProperty("java.version"); | |||
| private TtPayV2HttpClientBuilder() { | |||
| super(); | |||
| String userAgent = String.format( | |||
| "WechatPay-Apache-HttpClient/%s (%s) Java/%s", | |||
| getClass().getPackage().getImplementationVersion(), | |||
| OS, | |||
| VERSION == null ? "Unknown" : VERSION); | |||
| setUserAgent(userAgent); | |||
| } | |||
| public static TtPayV2HttpClientBuilder create() { | |||
| return new TtPayV2HttpClientBuilder(); | |||
| } | |||
| public TtPayV2HttpClientBuilder withAppId(String appId, String serialNo, PrivateKey privateKey) { | |||
| this.credentials = | |||
| new TtPayCredentials(appId, new PrivateKeySigner(serialNo, privateKey)); | |||
| return this; | |||
| } | |||
| public TtPayV2HttpClientBuilder withCredentials(Credentials credentials) { | |||
| this.credentials = credentials; | |||
| return this; | |||
| } | |||
| public TtPayV2HttpClientBuilder withPublicKey(PublicKey publicKey) { | |||
| this.validator = new TtPayValidator(new CertificatesVerifier(publicKey)); | |||
| return this; | |||
| } | |||
| public TtPayV2HttpClientBuilder withValidator(Validator validator) { | |||
| this.validator = validator; | |||
| return this; | |||
| } | |||
| @Override | |||
| public CloseableHttpClient build() { | |||
| if (credentials == null) { | |||
| throw new IllegalArgumentException("缺少身份认证信息"); | |||
| } | |||
| if (validator == null) { | |||
| throw new IllegalArgumentException("缺少签名验证信息"); | |||
| } | |||
| return super.build(); | |||
| } | |||
| @Override | |||
| protected ClientExecChain decorateProtocolExec(final ClientExecChain requestExecutor) { | |||
| return new SignatureExec(this.credentials, this.validator, requestExecutor); | |||
| } | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| package com.iformall.douyin.payv2.util; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import java.io.IOException; | |||
| public interface Validator { | |||
| boolean validate(CloseableHttpResponse response) throws IOException; | |||
| } | |||
| @@ -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<String, String> { | |||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
| protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | |||
| public TtWebGoodsGetRequestExecutor(RequestHttp requestHttp) { | |||
| this.requestHttp = requestHttp; | |||
| } | |||
| @Override | |||
| public void execute(String uri, String data, ResponseHandler<String> 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; | |||
| } | |||
| } | |||
| @@ -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<String, String> { | |||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
| protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | |||
| public TtWebGoodsPostRequestExecutor(RequestHttp requestHttp) { | |||
| this.requestHttp = requestHttp; | |||
| } | |||
| @Override | |||
| public void execute(String uri, String data, ResponseHandler<String> 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>")) { | |||
| // //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; | |||
| } | |||
| } | |||
| @@ -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<Product> 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<Product> 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 ; | |||
| } | |||
| @@ -110,4 +110,6 @@ public interface TtWebService { | |||
| */ | |||
| TtWebProductService getProductService(); | |||
| TtWebGoodsService getGoodsService(); | |||
| } | |||
| @@ -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<GoodsTemplateGet> baseResult = GSON.fromJson(result, | |||
| new TypeReference<BaseGoodsResult<GoodsTemplateGet>>(){}.getType()); | |||
| if(baseResult.isSuccess()){ | |||
| return baseResult.getData(); | |||
| }else{ | |||
| throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); | |||
| } | |||
| } | |||
| @Override | |||
| public List<Product> 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()){ | |||
| Map map = (Map) baseResult.getData(); | |||
| if(map != null){ | |||
| Object product_draft_list = map.get("product_draft_list"); | |||
| List<Product> list = GSON.fromJson(GSON.toJson(product_draft_list), | |||
| new TypeReference<List<Product>>() {}.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<ProductPage> baseResult = GSON.fromJson(result, | |||
| new TypeReference<BaseGoodsResult<ProductPage>>() {}.getType()); | |||
| if(baseResult.isSuccess()){ | |||
| return baseResult.getData(); | |||
| }else{ | |||
| throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); | |||
| } | |||
| } | |||
| @Override | |||
| public List<Product> 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()){ | |||
| Map map = (Map) baseResult.getData(); | |||
| if(map != null){ | |||
| Object product_online_list = map.get("product_online_list"); | |||
| List<Product> list = GSON.fromJson(GSON.toJson(product_online_list), | |||
| new TypeReference<List<Product>>() {}.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<ProductPage> baseResult = GSON.fromJson(result, | |||
| new TypeReference<BaseGoodsResult<ProductPage>>() {}.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()){ | |||
| Map map = (Map) baseResult.getData(); | |||
| return map.get("product_id").toString(); | |||
| }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<String,Object> 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<String,Object> 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<String,Object> 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<String,Integer> 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()); | |||
| } | |||
| } | |||
| } | |||
| @@ -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<CloseableHttp | |||
| private TtWebShopMatchService shopMatchService = new TtWebShopMatchServiceImpl(this); | |||
| private TtWebProductService productService = new TtWebProductServiceImpl(this); | |||
| private TtWebGoodsServiceImpl goodService = new TtWebGoodsServiceImpl(this); | |||
| private int retrySleepMillis = 1000; | |||
| private int maxRetryTimes = 5; | |||
| @@ -198,7 +200,7 @@ public class TtWebServiceImpl implements TtWebService, RequestHttp<CloseableHttp | |||
| if (error.getErrorCode() == -1) { | |||
| int sleepMillis = this.retrySleepMillis * (1 << retryTimes); | |||
| try { | |||
| log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||
| log.warn("系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||
| Thread.sleep(sleepMillis); | |||
| } catch (InterruptedException e1) { | |||
| Thread.currentThread().interrupt(); | |||
| @@ -294,4 +296,9 @@ public class TtWebServiceImpl implements TtWebService, RequestHttp<CloseableHttp | |||
| return this.productService; | |||
| } | |||
| @Override | |||
| public TtWebGoodsService getGoodsService() { | |||
| return this.goodService; | |||
| } | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| package com.iformall.douyin.web.bean; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| /** | |||
| * 商品. | |||
| * | |||
| * @author thinsstar | |||
| */ | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class BaseGoodsResult<T> 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<T> 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; | |||
| } | |||
| } | |||
| @@ -0,0 +1,91 @@ | |||
| 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> productAttrs; | |||
| /** | |||
| * SKU属性列表 | |||
| */ | |||
| @SerializedName(value = "sku_attrs") | |||
| private List<ProductAttrs> 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; | |||
| /** | |||
| * 是否展示 | |||
| */ | |||
| @SerializedName(value = "is_show") | |||
| private Boolean isShow; | |||
| /** | |||
| * 属性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; | |||
| @SerializedName(value = "data") | |||
| private String data; | |||
| } | |||
| } | |||
| @@ -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<PoiStruct> poiList; | |||
| /** | |||
| * 商品属性KV | |||
| */ | |||
| @SerializedName(value = "attr_key_value_map") | |||
| private Map<String,String> 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<String,String> 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; | |||
| } | |||
| } | |||
| @@ -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<Product> productList; | |||
| } | |||
| @@ -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<Product.SkuStruct> skuList; | |||
| } | |||
| @@ -7,8 +7,12 @@ public enum EnumCouponChannelStatus { | |||
| // 0-草稿/待生效;1-已生效/已发布/已投放;2-已下架; | |||
| STATUS_BEFORE(-1, "预上线"),//审核用 | |||
| STATUS_THROW_IN(0, "已上架"), | |||
| STATUS_TAKE_OFFF(1, "已下架"), | |||
| STATUS_AFTER(2, "作废"), | |||
| ; | |||
| public static EnumCouponChannelStatus getEnum(Integer code) { | |||
| @@ -25,6 +25,8 @@ public enum EnumMsgRecordType { | |||
| INSIDE_PRODUCT_PUSH(109, "商品状态或库存同步"), | |||
| MALL_COO_USER_PUSH(110, "猫酷同步会员"), | |||
| INSIDE_ORDER_PUSH_DELIVERY(200, "2.0核销同步"), | |||
| ; | |||
| public static EnumMsgRecordType getEnum(Integer code) { | |||
| @@ -5,10 +5,11 @@ package com.iformall.enums; | |||
| */ | |||
| public enum EnumPushType { | |||
| // 1-B端, 2-C端, 3-服务号, 4-订阅号 | |||
| // | |||
| SPU_STATUS_SYNC(1, "同步状态"), | |||
| SPU_STOCK_SYNC(2, "同步库存"), | |||
| SPU_FREE_AUDIT_SYNC(3, "免审修改"), | |||
| ; | |||
| public static EnumPushType getEnum(Integer code) { | |||
| @@ -11,6 +11,7 @@ public enum EnumSpuSyncStatus { | |||
| sync_pull_off(2, "下架"), | |||
| sync_audit_rejection(3, "审核拒绝"), | |||
| sync_audit_pass(4, "审核通过"), | |||
| sync_audit_disable(5, "封禁"), | |||
| ; | |||
| public static EnumSpuSyncStatus getEnum(Integer code) { | |||
| @@ -0,0 +1,52 @@ | |||
| package com.iformall.enums; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| /** | |||
| * Created by Stormeye on 2018/08/09. | |||
| */ | |||
| public enum EnumTtProductType { | |||
| //1 : 团购套餐 | |||
| //3 : 预售券 | |||
| //4 : 日历房 | |||
| //5 : 门票 | |||
| //7 : 旅行跟拍 | |||
| //8 : 一日游 | |||
| //11 : 代金券 | |||
| PRODUCT_TUANGOU(1, "团购套餐"), | |||
| PRODUCT_YUSHOU(3, "预售券"), | |||
| PRODUCT_RILI(4, "日历房"),//没用 | |||
| PRODUCT_MENGPIAO(5, "门票"), | |||
| PRODUCT_LVPAI(7, "旅行跟拍"), | |||
| PRODUCT_YIRIYOU(8, "一日游"), | |||
| PRODUCT_DAIJIN(11, "代金券"), | |||
| ; | |||
| public static EnumTtProductType getEnum(Integer code) { | |||
| for (EnumTtProductType value : values()) { | |||
| if (value.getCode().equals(code)) { | |||
| return value; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private Integer code; | |||
| private String message; | |||
| EnumTtProductType(Integer code, String message) { | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| public Integer getCode() { | |||
| return code; | |||
| } | |||
| public String getMessage() { | |||
| return message; | |||
| } | |||
| } | |||
| @@ -13,4 +13,10 @@ public interface TtCouponChannelPoiMapper extends CommonMapper<TtCouponChannelPo | |||
| List<Long> findIdList(TtCouponChannelPoi record); | |||
| Integer getPoiPutOnCount(@Param("tenantId")String tenantId, @Param("ids")List<Long> ids); | |||
| int updateBySpuId(TtCouponChannelPoi couponChannelPoi); | |||
| TtCouponChannelPoi selectById(@Param("tenantId")String tenantId,@Param("id")Long id); | |||
| TtCouponChannelPoi selectByChannelId(@Param("tenantId")String tenantId,@Param("couponChannelId")Long couponChannelId); | |||
| } | |||
| @@ -0,0 +1,13 @@ | |||
| package com.iformall.mapper; | |||
| import com.iformall.common.CommonMapper; | |||
| import com.iformall.domain.po.TtGoodsCategory; | |||
| import com.iformall.domain.po.WxSubBusiness; | |||
| import java.util.List; | |||
| public interface TtGoodsCategoryMapper extends CommonMapper<TtGoodsCategory, String> { | |||
| List<TtGoodsCategory> findListAll(); | |||
| } | |||
| @@ -5,6 +5,7 @@ import com.iformall.common.CommonMapper; | |||
| import com.iformall.domain.po.WxTopic; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.po.WxCouponChannel; | |||
| import com.iformall.domain.vo.TtCouponChannelVo; | |||
| import org.apache.ibatis.annotations.Param; | |||
| public interface WxCouponChannelMapper extends CommonMapper<WxCouponChannel, String> { | |||
| @@ -25,13 +26,13 @@ public interface WxCouponChannelMapper extends CommonMapper<WxCouponChannel, Str | |||
| int updateEndTimeByCouponId(WxCouponChannel wxCouponChannel); | |||
| List<Long> getExpiriedCouponChannelIdsByEndTime(@Param("tenantId")String tenantId);//同步poi状态 | |||
| List<Long> getExpiriedCouponIdsByEndTime(@Param("tenantId")String tenantId);//同步poi状态 | |||
| void offExpiriedCouponChannelByEndTime(@Param("tenantId")String tenantId); | |||
| List<Long> getExpiriedCouponChannelIdsByValidDate(@Param("tenantId")String tenantId);//同步poi状态 | |||
| List<Long> getExpiriedCouponIdsByValidDate(@Param("tenantId")String tenantId);//同步poi状态 | |||
| void offExpiriedCouponChannelByValidDate(@Param("tenantId")String tenantId); | |||
| List<Long> getExpiriedCouponChannelIdsByCouponStatus(@Param("tenantId")String tenantId);//同步poi状态 | |||
| List<Long> getExpiriedCouponIdsByCouponStatus(@Param("tenantId")String tenantId);//同步poi状态 | |||
| void offExpiriedCouponChannelByCouponStatus(@Param("tenantId")String tenantId); | |||
| void offExpiriedCouponChannel2ByEndTime(@Param("tenantId")String tenantId); | |||
| @@ -50,14 +51,6 @@ public interface WxCouponChannelMapper extends CommonMapper<WxCouponChannel, Str | |||
| List<WxCouponChannel> newfindCList(WxCouponChannel wxCouponChannel); | |||
| List<WxCouponChannel> liveHomeList(WxCouponChannel wxCouponChannel); | |||
| /** | |||
| * 查询已同步的上架卷的Id | |||
| * @param tenantId | |||
| * @param id | |||
| * @return | |||
| */ | |||
| List<Long> getPoiProductIdList(@Param("tenantId")String tenantId, @Param("couponId")Long couponId); | |||
| Integer reduceChannelStock(@Param("id")Long id,@Param("tenantId")String tenantId,@Param("number")Integer number); | |||
| @@ -72,4 +65,5 @@ public interface WxCouponChannelMapper extends CommonMapper<WxCouponChannel, Str | |||
| WxCouponChannel getPriceAndStock(@Param("id")Long id,@Param("tenantId")String tenantId); | |||
| List<WxCouponChannel> batGetPriceAndStock(@Param("ids")List<Long> ids,@Param("tenantId")String tenantId); | |||
| List<TtCouponChannelVo> ttChannelList(TtCouponChannelVo ttChannelVo); | |||
| } | |||