Browse Source

//tt push

release_toaliyun_real
xhxu 3 years ago
parent
commit
b1697b5e74
100 changed files with 7255 additions and 216 deletions
  1. +4
    -0
      mallinkAdmin/src/main/java/com/iformall/config/ShiroConfig.java
  2. +38
    -0
      mallinkAdmin/src/main/java/com/iformall/controller/basic/TtGoodsCategoryController.java
  3. +69
    -69
      mallinkAdmin/src/main/java/com/iformall/controller/basic/TtMerchantPoiController.java
  4. +76
    -0
      mallinkAdmin/src/main/java/com/iformall/controller/basic/WxProjectConfigController.java
  5. +184
    -0
      mallinkAdmin/src/main/java/com/iformall/controller/market/TtCouponGoodsController.java
  6. +18
    -0
      mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponChannelController.java
  7. +43
    -5
      mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java
  8. +1
    -1
      mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponOrderController.java
  9. +23
    -12
      mallinkAdmin/src/main/java/com/iformall/controller/market/WxOrderController.java
  10. +303
    -0
      mallinkAdmin/src/main/resources/db/migration/V2022052700002__push_order.sql
  11. +505
    -0
      mallinkAdmin/src/main/resources/db/migration/V2022060700001__coupon_product.sql
  12. +4
    -0
      mallinkAdmin/src/main/resources/db/migration/V2022061000001__banner_add.sql
  13. +43
    -0
      mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java
  14. +5
    -1
      mallinkCApi/src/main/java/com/iformall/controller/WxCouponController.java
  15. +1
    -1
      mallinkCApi/src/main/java/com/iformall/controller/WxCouponPasswordController.java
  16. +243
    -6
      mallinkCApi/src/main/java/com/iformall/controller/WxOrderController.java
  17. +28
    -3
      mallinkCApi/src/main/java/com/iformall/controller/WxPayOrderController.java
  18. +1
    -0
      mallinkCallback/src/main/java/com/iformall/config/ShiroConfig.java
  19. +1
    -1
      mallinkCallback/src/main/java/com/iformall/controller/callback/JinMaoController.java
  20. +104
    -33
      mallinkCallback/src/main/java/com/iformall/controller/callback/TtPayController.java
  21. +123
    -0
      mallinkCallback/src/main/java/com/iformall/controller/callback/TtWebController.java
  22. +7
    -0
      mallinkMQConsumer/src/main/java/com/iformall/mq/MqBaseConsumer.java
  23. +19
    -19
      mallinkSchedule/src/main/java/com/iformall/schedule/CouponExpiringSchedule.java
  24. +1
    -1
      mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java
  25. +76
    -0
      mallinkSchedule/src/main/java/com/iformall/schedule/OrderRefundAuditSchedule.java
  26. +2
    -2
      mallinkSchedule/src/main/java/com/iformall/schedule/SharingOrderRedoSchedule.java
  27. +2
    -2
      mallinkSchedule/src/main/java/com/iformall/schedule/SharingOrderResultSchedule.java
  28. +16
    -16
      mallinkSchedule/src/main/java/com/iformall/schedule/TtMerchantPoiSchedule.java
  29. +2
    -2
      mallinkSchedule/src/main/java/com/iformall/schedule/TtOrderPushErrorSchedule.java
  30. +32
    -0
      mallinkService/src/main/java/com/iformall/domain/dto/PlatPushOrderSaveDto.java
  31. +5
    -1
      mallinkService/src/main/java/com/iformall/domain/po/TtCouponChannelPoi.java
  32. +29
    -0
      mallinkService/src/main/java/com/iformall/domain/po/TtGoodsCategory.java
  33. +17
    -0
      mallinkService/src/main/java/com/iformall/domain/po/WxBatchOrder.java
  34. +55
    -1
      mallinkService/src/main/java/com/iformall/domain/po/WxCoupon.java
  35. +18
    -0
      mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java
  36. +4
    -0
      mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java
  37. +17
    -0
      mallinkService/src/main/java/com/iformall/domain/po/WxOrder.java
  38. +3
    -0
      mallinkService/src/main/java/com/iformall/domain/po/msg/FmInsideOrderPushMsg.java
  39. +2
    -2
      mallinkService/src/main/java/com/iformall/domain/po/msg/FmInsideProductPushMsg.java
  40. +41
    -0
      mallinkService/src/main/java/com/iformall/domain/vo/TtCouponChannelVo.java
  41. +34
    -0
      mallinkService/src/main/java/com/iformall/domain/vo/TtCouponVo.java
  42. +2
    -0
      mallinkService/src/main/java/com/iformall/domain/vo/WxCouponOrderBVo.java
  43. +5
    -0
      mallinkService/src/main/java/com/iformall/domain/vo/WxMerchantVo.java
  44. +27
    -25
      mallinkService/src/main/java/com/iformall/douyin/pay/DouYinPayHelper.java
  45. +48
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/ProfitSharingV2Service.java
  46. +201
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/TtPayService.java
  47. +216
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/exception/TtPayException.java
  48. +255
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/impl/BaseTtPayServiceImpl.java
  49. +76
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/impl/ProfitSharingV2ServiceImpl.java
  50. +155
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/impl/TtPayServiceApacheHttpImpl.java
  51. +11
    -0
      mallinkService/src/main/java/com/iformall/douyin/pay/impl/TtPayServiceImpl.java
  52. +72
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/auth/CertificatesVerifier.java
  53. +35
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/auth/PrivateKeySigner.java
  54. +15
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/auth/Signer.java
  55. +91
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/auth/TtPayCredentials.java
  56. +55
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/auth/TtPayValidator.java
  57. +6
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/auth/Verifier.java
  58. +179
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/config/TtPayConfig.java
  59. +35
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/CallBackSettingsRequest.java
  60. +67
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/ProfitSharingRequest.java
  61. +73
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtOrderPushDeliveryRequest.java
  62. +38
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayOrderQueryV2Request.java
  63. +36
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayRefundQueryV2Request.java
  64. +107
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayRefundV2Request.java
  65. +456
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayUnifiedOrderV2Request.java
  66. +64
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtRefundAuditMsgRequest.java
  67. +55
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/BaseTtPayResult.java
  68. +226
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/CreateOrderCallback.java
  69. +32
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/OriginNotifyResponse.java
  70. +112
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/ProfitSharingResult.java
  71. +138
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/RefundOrderCallback.java
  72. +304
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayCpsOrderQueryV2Result.java
  73. +119
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayOrderQueryV2Result.java
  74. +121
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayRefundQueryV2Result.java
  75. +33
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayRefundV2Result.java
  76. +99
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayUnifiedOrderV2Result.java
  77. +12
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/util/Credentials.java
  78. +89
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/util/PemUtils.java
  79. +81
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/util/SignatureExec.java
  80. +70
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/util/TtPayV2HttpClientBuilder.java
  81. +9
    -0
      mallinkService/src/main/java/com/iformall/douyin/payv2/util/Validator.java
  82. +108
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsGetRequestExecutor.java
  83. +117
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsPostRequestExecutor.java
  84. +144
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsService.java
  85. +2
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebService.java
  86. +254
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebGoodsServiceImpl.java
  87. +8
    -1
      mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebServiceImpl.java
  88. +90
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/bean/BaseGoodsResult.java
  89. +91
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/bean/GoodsTemplateGet.java
  90. +252
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/bean/Product.java
  91. +40
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductPage.java
  92. +40
    -0
      mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductSku.java
  93. +4
    -0
      mallinkService/src/main/java/com/iformall/enums/EnumCouponChannelStatus.java
  94. +2
    -0
      mallinkService/src/main/java/com/iformall/enums/EnumMsgRecordType.java
  95. +2
    -1
      mallinkService/src/main/java/com/iformall/enums/EnumPushType.java
  96. +1
    -0
      mallinkService/src/main/java/com/iformall/enums/EnumSpuSyncStatus.java
  97. +52
    -0
      mallinkService/src/main/java/com/iformall/enums/EnumTtProductType.java
  98. +6
    -0
      mallinkService/src/main/java/com/iformall/mapper/TtCouponChannelPoiMapper.java
  99. +13
    -0
      mallinkService/src/main/java/com/iformall/mapper/TtGoodsCategoryMapper.java
  100. +5
    -11
      mallinkService/src/main/java/com/iformall/mapper/WxCouponChannelMapper.java

+ 4
- 0
mallinkAdmin/src/main/java/com/iformall/config/ShiroConfig.java View File

@@ -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");


+ 38
- 0
mallinkAdmin/src/main/java/com/iformall/controller/basic/TtGoodsCategoryController.java View File

@@ -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());
}

}

+ 69
- 69
mallinkAdmin/src/main/java/com/iformall/controller/basic/TtMerchantPoiController.java View File

@@ -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);
// }

}

+ 76
- 0
mallinkAdmin/src/main/java/com/iformall/controller/basic/WxProjectConfigController.java View File

@@ -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);
}
}

}

+ 184
- 0
mallinkAdmin/src/main/java/com/iformall/controller/market/TtCouponGoodsController.java View File

@@ -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);
}



}

+ 18
- 0
mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponChannelController.java View File

@@ -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查询接口")


+ 43
- 5
mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java View File

@@ -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 = "券投放-库存/有效期更新")


+ 1
- 1
mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponOrderController.java View File

@@ -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);
}

}

+ 23
- 12
mallinkAdmin/src/main/java/com/iformall/controller/market/WxOrderController.java View File

@@ -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));

}


}

+ 303
- 0
mallinkAdmin/src/main/resources/db/migration/V2022052700002__push_order.sql View File

@@ -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 '额外参数,用于第三方平台';


+ 505
- 0
mallinkAdmin/src/main/resources/db/migration/V2022060700001__coupon_product.sql View File

@@ -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`;

+ 4
- 0
mallinkAdmin/src/main/resources/db/migration/V2022061000001__banner_add.sql View File

@@ -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;

+ 43
- 0
mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java View File

@@ -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);
}
}

+ 5
- 1
mallinkCApi/src/main/java/com/iformall/controller/WxCouponController.java View File

@@ -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);


+ 1
- 1
mallinkCApi/src/main/java/com/iformall/controller/WxCouponPasswordController.java View File

@@ -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));


+ 243
- 6
mallinkCApi/src/main/java/com/iformall/controller/WxOrderController.java View File

@@ -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;

}

}

+ 28
- 3
mallinkCApi/src/main/java/com/iformall/controller/WxPayOrderController.java View File

@@ -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) {


+ 1
- 0
mallinkCallback/src/main/java/com/iformall/config/ShiroConfig.java View File

@@ -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");



+ 1
- 1
mallinkCallback/src/main/java/com/iformall/controller/callback/JinMaoController.java View File

@@ -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 ;


+ 104
- 33
mallinkCallback/src/main/java/com/iformall/controller/callback/TtPayController.java View File

@@ -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;


+ 123
- 0
mallinkCallback/src/main/java/com/iformall/controller/callback/TtWebController.java View File

@@ -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;
}

}

+ 7
- 0
mallinkMQConsumer/src/main/java/com/iformall/mq/MqBaseConsumer.java View File

@@ -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);


+ 19
- 19
mallinkSchedule/src/main/java/com/iformall/schedule/CouponExpiringSchedule.java View File

@@ -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());
}


+ 1
- 1
mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java View File

@@ -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());

}



+ 76
- 0
mallinkSchedule/src/main/java/com/iformall/schedule/OrderRefundAuditSchedule.java View File

@@ -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();
}
}

}

}
}


}

+ 2
- 2
mallinkSchedule/src/main/java/com/iformall/schedule/SharingOrderRedoSchedule.java View File

@@ -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) {


+ 2
- 2
mallinkSchedule/src/main/java/com/iformall/schedule/SharingOrderResultSchedule.java View File

@@ -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) {


+ 16
- 16
mallinkSchedule/src/main/java/com/iformall/schedule/TtMerchantPoiSchedule.java View File

@@ -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("查询商品同步任务失败");
// }
// }
// }
// }

}

+ 2
- 2
mallinkSchedule/src/main/java/com/iformall/schedule/TtOrderPushErrorSchedule.java View File

@@ -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");
}


+ 32
- 0
mallinkService/src/main/java/com/iformall/domain/dto/PlatPushOrderSaveDto.java View File

@@ -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;//【非传入参数】。

}

+ 5
- 1
mallinkService/src/main/java/com/iformall/domain/po/TtCouponChannelPoi.java View File

@@ -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;



+ 29
- 0
mallinkService/src/main/java/com/iformall/domain/po/TtGoodsCategory.java View File

@@ -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;


}

+ 17
- 0
mallinkService/src/main/java/com/iformall/domain/po/WxBatchOrder.java View File

@@ -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);
}

}

+ 55
- 1
mallinkService/src/main/java/com/iformall/domain/po/WxCoupon.java View File

@@ -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;


+ 18
- 0
mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java View File

@@ -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;


+ 4
- 0
mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java View File

@@ -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;


+ 17
- 0
mallinkService/src/main/java/com/iformall/domain/po/WxOrder.java View File

@@ -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;


+ 3
- 0
mallinkService/src/main/java/com/iformall/domain/po/msg/FmInsideOrderPushMsg.java View File

@@ -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;

}

+ 2
- 2
mallinkService/src/main/java/com/iformall/domain/po/msg/FmInsideProductPushMsg.java View File

@@ -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;


+ 41
- 0
mallinkService/src/main/java/com/iformall/domain/vo/TtCouponChannelVo.java View File

@@ -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;

}

+ 34
- 0
mallinkService/src/main/java/com/iformall/domain/vo/TtCouponVo.java View File

@@ -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;
}

+ 2
- 0
mallinkService/src/main/java/com/iformall/domain/vo/WxCouponOrderBVo.java View File

@@ -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;


+ 5
- 0
mallinkService/src/main/java/com/iformall/domain/vo/WxMerchantVo.java View File

@@ -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();


+ 27
- 25
mallinkService/src/main/java/com/iformall/douyin/pay/DouYinPayHelper.java View File

@@ -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());


+ 48
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/ProfitSharingV2Service.java View File

@@ -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;

}

+ 201
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/TtPayService.java View File

@@ -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();

}

+ 216
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/exception/TtPayException.java View File

@@ -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
);
}
}
}

+ 255
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/impl/BaseTtPayServiceImpl.java View File

@@ -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();
}
}

}

+ 76
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/impl/ProfitSharingV2ServiceImpl.java View File

@@ -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());
}
}

+ 155
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/impl/TtPayServiceApacheHttpImpl.java View File

@@ -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;
}

}

+ 11
- 0
mallinkService/src/main/java/com/iformall/douyin/pay/impl/TtPayServiceImpl.java View File

@@ -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 {
}

+ 72
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/auth/CertificatesVerifier.java View File

@@ -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();
// }
// }

}

+ 35
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/auth/PrivateKeySigner.java View File

@@ -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);
}
}
}

+ 15
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/auth/Signer.java View File

@@ -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;
}
}
}

+ 91
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/auth/TtPayCredentials.java View File

@@ -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";
}

}

+ 55
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/auth/TtPayValidator.java View File

@@ -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) : "";
}
}

+ 6
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/auth/Verifier.java View File

@@ -0,0 +1,6 @@
package com.iformall.douyin.payv2.auth;

public interface Verifier {
boolean verify(byte[] message, String signature);

}

+ 179
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/config/TtPayConfig.java View File

@@ -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;
}
}

+ 35
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/CallBackSettingsRequest.java View File

@@ -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;

}

+ 67
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/ProfitSharingRequest.java View File

@@ -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;

}

+ 73
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtOrderPushDeliveryRequest.java View File

@@ -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;

}
}

+ 38
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayOrderQueryV2Request.java View File

@@ -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;
}

+ 36
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayRefundQueryV2Request.java View File

@@ -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;

}

+ 107
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayRefundV2Request.java View File

@@ -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;

}
}

+ 456
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtPayUnifiedOrderV2Request.java View File

@@ -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;

}

}

+ 64
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/request/TtRefundAuditMsgRequest.java View File

@@ -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;

}
}

+ 55
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/BaseTtPayResult.java View File

@@ -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);
}

}

+ 226
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/CreateOrderCallback.java View File

@@ -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;

}

}

+ 32
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/OriginNotifyResponse.java View File

@@ -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;

}

+ 112
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/ProfitSharingResult.java View File

@@ -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;
}
}

+ 138
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/RefundOrderCallback.java View File

@@ -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;

}

}

+ 304
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayCpsOrderQueryV2Result.java View File

@@ -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;

}

}

+ 119
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayOrderQueryV2Result.java View File

@@ -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;

}

+ 121
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayRefundQueryV2Result.java View File

@@ -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;
}
}

+ 33
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayRefundV2Result.java View File

@@ -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;

}

+ 99
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/result/TtPayUnifiedOrderV2Result.java View File

@@ -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;
}



}

+ 12
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/util/Credentials.java View File

@@ -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;
}

+ 89
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/util/PemUtils.java View File

@@ -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("无效的密钥");
}
}
}

+ 81
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/util/SignatureExec.java View File

@@ -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;
}

}

+ 70
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/util/TtPayV2HttpClientBuilder.java View File

@@ -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);
}
}

+ 9
- 0
mallinkService/src/main/java/com/iformall/douyin/payv2/util/Validator.java View File

@@ -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;
}

+ 108
- 0
mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsGetRequestExecutor.java View File

@@ -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;
}

}

+ 117
- 0
mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsPostRequestExecutor.java View File

@@ -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;
}
}

+ 144
- 0
mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsService.java View File

@@ -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 ;

}

+ 2
- 0
mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebService.java View File

@@ -110,4 +110,6 @@ public interface TtWebService {
*/
TtWebProductService getProductService();

TtWebGoodsService getGoodsService();

}

+ 254
- 0
mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebGoodsServiceImpl.java View File

@@ -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());
}
}
}

+ 8
- 1
mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebServiceImpl.java View File

@@ -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;
}

}

+ 90
- 0
mallinkService/src/main/java/com/iformall/douyin/web/bean/BaseGoodsResult.java View File

@@ -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;

}

}

+ 91
- 0
mallinkService/src/main/java/com/iformall/douyin/web/bean/GoodsTemplateGet.java View File

@@ -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;

}

}

+ 252
- 0
mallinkService/src/main/java/com/iformall/douyin/web/bean/Product.java View File

@@ -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;

}

}

+ 40
- 0
mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductPage.java View File

@@ -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;

}

+ 40
- 0
mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductSku.java View File

@@ -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;

}

+ 4
- 0
mallinkService/src/main/java/com/iformall/enums/EnumCouponChannelStatus.java View File

@@ -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) {


+ 2
- 0
mallinkService/src/main/java/com/iformall/enums/EnumMsgRecordType.java View File

@@ -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) {


+ 2
- 1
mallinkService/src/main/java/com/iformall/enums/EnumPushType.java View File

@@ -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) {


+ 1
- 0
mallinkService/src/main/java/com/iformall/enums/EnumSpuSyncStatus.java View File

@@ -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) {


+ 52
- 0
mallinkService/src/main/java/com/iformall/enums/EnumTtProductType.java View File

@@ -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;
}

}

+ 6
- 0
mallinkService/src/main/java/com/iformall/mapper/TtCouponChannelPoiMapper.java View File

@@ -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);
}

+ 13
- 0
mallinkService/src/main/java/com/iformall/mapper/TtGoodsCategoryMapper.java View File

@@ -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
- 11
mallinkService/src/main/java/com/iformall/mapper/WxCouponChannelMapper.java View File

@@ -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);
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save