5 Commits
prod ... pay

Author SHA1 Message Date
gong
2046ad2486 微信支付- dto 注释 2025-12-26 16:53:57 +08:00
gong
0cdad226ea 微信支付- dto222 2025-12-26 16:23:46 +08:00
gong
e179a910ba 微信支付- dto1 2025-12-26 15:13:11 +08:00
gong
6b5c451f92 微信支付- dto 2025-12-26 15:08:21 +08:00
gong
303db8bc49 微信支付-上传图片 2025-12-26 11:38:48 +08:00
54 changed files with 2089 additions and 197 deletions

View File

@@ -0,0 +1,39 @@
package com.czg.controller;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserFlowService;
import com.czg.account.service.ShopUserService;
import com.czg.account.service.TestService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author GYJoker
*/
@RestController
@RequestMapping("/notify/test")
public class TestController {
@Resource
private ShopUserFlowService shopUserFlowService;
@Resource
private ShopInfoService shopInfoService;
@Resource
private ShopUserService shopUserService;
@Resource
private TestService testService;
@RequestMapping("/hello")
public String hello() {
shopUserFlowService.list().forEach(item -> {
ShopUser shopUserInfo = shopUserService.getShopUserInfo(item.getShopId(), item.getUserId());
if (shopUserInfo != null) {
item.setShopUserId(shopUserInfo.getId());
shopUserFlowService.updateById(item);
}
});
// return testService.insertData();
return "";
}
}

View File

@@ -13,7 +13,6 @@ import com.czg.market.vo.InviteUserVO;
import com.czg.market.vo.MkDistributionConfigVO;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.task.DistributionTask;
import com.czg.utils.AssertUtil;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
@@ -38,22 +37,6 @@ public class UDistributionController {
private MkDistributionWithdrawFlowService withdrawFlowService;
@Resource
private MkDistributionFlowService distributionFlowService;
@Resource
private DistributionTask distributionTask;
/**
* 分销员中心-获取配置
*/
@GetMapping("/task")
public CzgResult<String> task(@RequestParam Long shopId) {
try {
distributionTask.deliver(shopId);
} catch (Exception e) {
return CzgResult.failure(e.getMessage());
}
return CzgResult.success("任务执行成功");
}
/**
* 分销员中心-获取配置

View File

@@ -6,7 +6,6 @@ import org.springframework.stereotype.Component;
/**
* market服务 任务总调度
*
* @author ww
*/
@Component
@@ -19,9 +18,9 @@ public class AAMarketTasks {
// 分销延时发放
@Scheduled(cron = "0 0 0/2 * * ? ")
@Scheduled(fixedRate = 30000)
public void distributionTask() {
distributionTask.deliver(null);
distributionTask.deliver();
}
@@ -30,7 +29,6 @@ public class AAMarketTasks {
public void birthdayGiftTask() {
birthdayGiftTask.deliver();
}
//会员生日弹窗提醒重置 每年1月1日
@Scheduled(cron = "0 0 0 1 1 ?")
public void birthdayGiftRemindTask() {
@@ -41,7 +39,6 @@ public class AAMarketTasks {
//优惠券 过期
@Resource
private CouponTask couponTask;
//每天每小时的30分 0秒 执行
@Scheduled(cron = "0 30 * * * ? ")
public void couponTask() {
@@ -51,7 +48,6 @@ public class AAMarketTasks {
//会员奖励发放
@Resource
private MemberTask memberTask;
//每天1点 0分 0秒 执行
@Scheduled(cron = "0 0 1 * * ? ")
public void memberTask() {
@@ -61,7 +57,6 @@ public class AAMarketTasks {
//满减活动/限时折扣 处理任务状态 定时任务
@Resource
private ActivityStatusTask activityStatusTask;
//每天0点 0分 1秒 执行
@Scheduled(cron = "1 0 0 * * ? ")
public void activityStatusTask() {
@@ -72,7 +67,6 @@ public class AAMarketTasks {
//月累计 发送条数 累计金额
@Resource
private SmsShopMoneyTask smsShopMoneyTask;
//每月1号 0点 0分 1秒 执行
@Scheduled(cron = "1 0 0 1 * ?")
public void smsShopMoneyTask() {

View File

@@ -2,13 +2,10 @@ package com.czg.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.constant.TableValueConstant;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.market.entity.MkDistributionFlow;
import com.czg.market.service.MkDistributionFlowService;
import com.czg.market.service.MkDistributionUserService;
@@ -21,7 +18,6 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -44,6 +40,8 @@ public class DistributionTask {
private OrderInfoService orderInfoService;
@DubboReference
private ShopInfoService shopInfoService;
@DubboReference
private ShopUserService shopUserService;
List<String> list = List.of(OrderStatusEnums.REFUND.getCode(), OrderStatusEnums.PART_REFUND.getCode());
@@ -53,55 +51,44 @@ public class DistributionTask {
*/
// @Scheduled(cron = "0 0 0 * * ?")
// @Scheduled(fixedRate = 30000)
public void deliver(Long shopId) {
LocalDateTime now = LocalDateTime.now();
List<ShopInfo> shopInfos = shopInfoService.list(QueryWrapper.create()
.eq(ShopInfo::getIsDeleted, SystemConstants.OneZero.ZERO)
.isNotNull(ShopInfo::getExpireTime)
.lt(ShopInfo::getExpireTime, now)
.gt(ShopInfo::getAmount, BigDecimal.ZERO)
.eq(ShopInfo::getId, shopId)
);
if (CollUtil.isEmpty(shopInfos)) {
log.info("分销延时分账 无符合条件的店铺,无需处理分账");
return;
}
for (ShopInfo shopInfo : shopInfos) {
boolean breakCurrentShopFlow = false;
List<MkDistributionFlow> flowList = distributionFlowService.list(new QueryWrapper()
.eq(MkDistributionFlow::getShopId, shopInfo.getId())
.eq(MkDistributionFlow::getStatus, TableValueConstant.DistributionFlow.Status.PENDING.getCode())
.le(MkDistributionFlow::getDeliverTime, now)
.orderBy(MkDistributionFlow::getId, true)
);
for (MkDistributionFlow item : flowList) {
if (breakCurrentShopFlow) {
break;
public void deliver() {
// 1. 订单完成支付时(判断是否分销)产生流水记录。
// 2. 判断入账时间。
// 3. 如果是 0 天,再去判断商户余额是否足够。够则入账,不足则不管。
// 4. 流水增加应该入账的时间(订单产生时带入)
// 5. 定时任务 应该是一天执行一次。查询待入账状态和应入账时间小于当前时间的记录,循环处理:并且判断商户余额是否足够,余额不足忽略处理;余额足够变为已入账并扣除商户余额。
// 6. 订单产生退款时,去流水表查询该订单的流水记录,如果未入账改为已入账,并插入一条退款扣钱的流水。
// shopInfo 查余额>0
// 循环 shopId 查询 如果金额不足 终止
//
LocalDateTime localDateTime = DateUtil.date().toLocalDateTime();
distributionFlowService.list(new QueryWrapper()
.eq(MkDistributionFlow::getStatus, TableValueConstant.DistributionFlow.Status.PENDING.getCode()).le(MkDistributionFlow::getDeliverTime, localDateTime)).forEach(item -> {
FunUtils.safeRunVoid(() -> {
log.info("开始处理延时分账, id: {}, orderNo: {}, 类型: {}", item.getId(), item.getOrderNo(), item.getType());
OrderInfo orderInfo = orderInfoService.getOne(new QueryWrapper().eq(OrderInfo::getOrderNo, item.getOrderNo()));
if (orderInfo == null) {
item.setStatus(TableValueConstant.DistributionFlow.Status.FAIL.getCode());
distributionFlowService.updateById(item);
log.warn("订单不存在, 订单号: {}", item.getOrderNo());
return;
}
try {
log.info("分销延时分账, id: {}, orderNo: {}, 类型: {}", item.getId(), item.getOrderNo(), item.getType());
OrderInfo orderInfo = orderInfoService.getOne(new QueryWrapper().eq(OrderInfo::getOrderNo, item.getOrderNo()));
if (orderInfo == null) {
item.setStatus(TableValueConstant.DistributionFlow.Status.FAIL.getCode());
distributionFlowService.updateById(item);
log.warn("分销延时分账。订单不存在, 订单号: {}", item.getOrderNo());
continue;
}
if (list.contains(orderInfo.getStatus())) {
log.warn("分销延时分账。订单已退款, 订单号: {}", item.getOrderNo());
distributionUserService.refund(orderInfo.getId(), orderInfo.getOrderNo());
} else {
item.setStatus(TableValueConstant.DistributionFlow.Status.SUCCESS.getCode());
distributionUserService.distributionUserAmount(item, orderInfo);
}
} catch (CzgException e) {
log.error("店铺{}:{}分销延时分账异常:{}", shopInfo.getId(), shopInfo.getShopName(), e.getMessage());
breakCurrentShopFlow = true;
} catch (Exception e) {
log.error("店铺{}:{}分销延时分账异常", shopInfo.getId(), shopInfo.getShopName(), e);
breakCurrentShopFlow = true;
if (list.contains(orderInfo.getStatus())) {
log.warn("订单已退款, 订单号: {}", item.getOrderNo());
distributionUserService.refund(orderInfo.getId(), orderInfo.getOrderNo());
} else {
item.setStatus(TableValueConstant.DistributionFlow.Status.SUCCESS.getCode());
ShopUser shopUser = shopUserService.getById(item.getDistributionUserId());
distributionUserService.updateShopInfoAmount(orderInfo.getShopId(), item.getRewardAmount().negate(), orderInfo.getId(), TableValueConstant.DistributionAmountFlow.Type.SUB, "分销扣减");
distributionUserService.updateIncome(item.getRewardAmount().negate(), item.getRewardAmount(), BigDecimal.ZERO,
item.getDistributionUserId(), shopUser.getUserId(), item.getShopUserId(), item.getShopId(), item.getLevel());
distributionFlowService.updateById(item);
}
}
}
});
});
}
}

View File

@@ -50,8 +50,6 @@ public class NotifyController {
@Resource
private MkShopConsumeDiscountRecordService consumeDiscountRecordService;
//新客立减清除数据 测试用
@RequestMapping("clear")
public String clear(@RequestParam Integer shopId) {
consumeDiscountRecordService.remove(new QueryWrapper().eq(MkShopConsumeDiscountRecord::getShopId, shopId));

View File

@@ -21,7 +21,7 @@ public class StatisticTaskController {
private StatisticTask statisticTask;
/**
* 基础统计 预留重置统计
* 基础统计
*
* @param date 日期yyyy-MM-dd
*/

View File

@@ -39,7 +39,7 @@ public class OTimeTask {
@Resource
private CashierCartService cartService;
@Resource
private OrderPaymentService paymentService;
private OrderPaymentService orderPaymentService;
@Resource
private GbOrderService gbOrderService;
@Resource
@@ -117,7 +117,7 @@ public class OTimeTask {
LocalDateTime tenMinutesAgo = LocalDateTime.now().minusMinutes(10);
LocalDateTime thirdDayAgo = LocalDateTime.now().minusDays(3);
List<OrderPayment> list = paymentService.list(QueryWrapper.create()
List<OrderPayment> list = orderPaymentService.list(QueryWrapper.create()
.gt(OrderPayment::getUpdateTime, thirdDayAgo)
.lt(OrderPayment::getUpdateTime, tenMinutesAgo)
.in(OrderPayment::getSourceType, ware)

View File

@@ -1,6 +1,5 @@
package com.czg.config;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.audit.AuditManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
@@ -18,24 +17,8 @@ public class MybatisFlexConfig {
//设置 SQL 审计收集器
AuditManager.setMessageCollector(auditMessage ->
log.info("[sql] time: {}, size: {}, sql:\n{}",
auditMessage.getElapsedTime(), auditMessage.getQueryCount(), compressSql(auditMessage.getFullSql())));
auditMessage.getElapsedTime(), auditMessage.getQueryCount(), auditMessage.getFullSql())
);
}
/**
* 精简SQL去除多余换行、制表符、连续空格保留语法必需空格
*
* @param originalSql 原始带换行/空格的SQL
* @return 精简后的SQL
*/
public static String compressSql(String originalSql) {
if (StrUtil.isBlank(originalSql)) {
return "";
}
// 1. 替换所有换行、制表符为单个空格
String tempSql = originalSql.replaceAll("\\r\\n|\\r|\\n|\\t", " ");
// 2. 替换多个连续空格为单个空格
tempSql = tempSql.replaceAll("\\s+", " ");
// 3. 去除首尾空格
return tempSql.trim();
}
}

View File

@@ -7,12 +7,10 @@ import com.czg.exception.CzgException;
import com.czg.market.dto.MkDistributionUserDTO;
import com.czg.market.dto.MkDistributionWithdrawFlowDTO;
import com.czg.market.entity.MkDistributionConfig;
import com.czg.market.entity.MkDistributionFlow;
import com.czg.market.entity.MkDistributionUser;
import com.czg.market.vo.DistributionCenterShopVO;
import com.czg.market.vo.InviteUserVO;
import com.czg.order.dto.MkDistributionPayDTO;
import com.czg.order.entity.OrderInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
@@ -125,8 +123,6 @@ public interface MkDistributionUserService extends IService<MkDistributionUser>
void refund(Long orderId, String orderNo);
void distributionUserAmount(MkDistributionFlow item, OrderInfo orderInfo);
/**
* 发放分销奖励
*

View File

@@ -1,7 +1,6 @@
package com.czg.market.service;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkShopRechargeDTO;
import com.czg.market.vo.MkShopRechargeShopListVO;
import com.czg.market.vo.MkShopRechargeVO;
@@ -22,7 +21,7 @@ import java.util.List;
*/
public interface MkShopRechargeService extends IService<MkShopRecharge> {
MkShopRechargeVO detail(Long shopId) throws CzgException;
MkShopRechargeVO detail(Long shopId);
MkShopRechargeVO detailApp(Long shopId);

View File

@@ -81,7 +81,7 @@ public class OrderPayment implements Serializable {
*/
private String tradeNumber;
// @Column(onUpdateValue = "now()")
@Column(onUpdateValue = "now()")
private LocalDateTime payTime;
/**

View File

@@ -41,7 +41,6 @@ public class OrderDetailSmallVO implements Serializable {
private LocalDateTime startOrderTime;
private LocalDateTime dishOutTime;
private LocalDateTime foodServeTime;
private Integer isTemporary;
}

View File

@@ -42,6 +42,7 @@
<pinyin.version>2.5.1</pinyin.version>
<IJPay.version>2.9.10</IJPay.version>
<netty.version>4.1.128.Final</netty.version>
<wechatpay.version>0.2.17</wechatpay.version>
</properties>
<dependencyManagement>
@@ -268,6 +269,12 @@
<artifactId>netty-codec-mqtt</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>${wechatpay.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.czg</groupId>
<artifactId>cash-sdk</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>aggregation-pay</artifactId>
<packaging>jar</packaging>
<name>聚合支付</name>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,47 @@
package com.czg.wechat;
import com.czg.wechat.dto.config.WechatPayConfigDto;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.service.file.FileUploadService;
/**
* 微信支付 配置
*
* @author yjjie
* @date 2025/12/26 09:33
*/
public class WechatConfig {
/**
* 获取微信支付配置
* @param dto 微信支付配置
* @return 微信支付配置
*/
public static Config getConfig(WechatPayConfigDto dto) {
return new RSAPublicKeyConfig.Builder()
.merchantId(dto.getMerchantId())
.privateKey(dto.getPrivateKey())
.publicKey(dto.getPublicKey())
.publicKeyId(dto.getPublicKeyId())
.merchantSerialNumber(dto.getSerialNumber())
.apiV3Key(dto.getApiV3Key())
.build();
}
public static FileUploadService getFileUploadService(Config config) {
return new FileUploadService.Builder()
.config(config)
.build();
}
/**
* 获取文件上传服务
* @param dto 微信支付配置
* @return 文件上传服务
*/
public static FileUploadService getFileUploadService(WechatPayConfigDto dto) {
return getFileUploadService(getConfig(dto));
}
}

View File

@@ -0,0 +1,47 @@
package com.czg.wechat;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 微信支付加解密
* @author yjjie
* @date 2025/12/26 10:58
*/
public class WechatEncrypt {
public static String getFileBytesSha256(byte[] input) throws NoSuchAlgorithmException {
return bytesToHex(calculateSha256(input));
}
/**
* 核心方法:计算字节数组的 SHA-256 哈希值
* @param input 待计算的字节数组
* @return SHA-256 哈希值32 字节的字节数组)
*/
private static byte[] calculateSha256(byte[] input) throws NoSuchAlgorithmException {
// 获取 SHA-256 消息摘要实例Java 21 完全兼容)
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// 计算哈希值
return digest.digest(input);
}
/**
* 辅助方法将字节数组转换为十六进制字符串SHA-256 结果常用格式)
* @param bytes 待转换的字节数组
* @return 十六进制字符串SHA-256 对应 64 位字符串)
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
// Java 21 可使用 var 简化声明
for (var b : bytes) {
// 将字节转换为两位十六进制数,不足补 0
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}

View File

@@ -0,0 +1,162 @@
package com.czg.wechat;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.wechat.dto.config.WechatPayConfigDto;
import com.czg.wechat.dto.req.entry.WechatEntryReqDto;
import com.wechat.pay.java.service.file.FileUploadService;
import com.wechat.pay.java.service.file.model.FileUploadResponse;
import lombok.extern.slf4j.Slf4j;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
/**
* 微信支付进件 管理
*
* @author yjjie
* @date 2025/12/26 10:57
*/
@Slf4j
public class WechatEntryManager {
public static String uploadImage(WechatPayConfigDto configDto, String url) {
// 校验入参
if (configDto == null || url == null || url.trim().isEmpty()) {
log.error("上传图片失败配置或URL参数为空");
return "";
}
FileUploadService service = WechatConfig.getFileUploadService(configDto);
try {
// 获取图片字节数组
byte[] bytes = downloadImage(url);
if (bytes.length == 0) {
log.error("下载的图片内容为空URL{}", url);
return "";
}
// 2. 计算SHA256
String sha256Hex = WechatEncrypt.getFileBytesSha256(bytes);
// 3. 构造元数据从URL提取文件名或自定义
JSONObject meta = new JSONObject();
meta.put("sha256", sha256Hex);
// 从URL提取文件名若提取失败则使用默认名
String fileName = extractFileNameFromUrl(url);
meta.put("filename", fileName);
// 4. 上传图片到微信接口
FileUploadResponse uploadResponse = service.uploadImage(
configDto.getDomain() + "/v3/merchant/media/upload",
meta.toJSONString(),
fileName,
bytes
);
return uploadResponse.getMediaId();
} catch (Exception e) {
log.error("微信上传图片报错URL{},错误信息:{}", url, e.getMessage(), e);
}
return "";
}
public static byte[] downloadImage(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
throw new RuntimeException("Failed to download image, status code: " + response.statusCode());
}
return response.body();
}
/**
* 从URL中提取文件名
*
* @param url 图片URL
* @return 提取的文件名,失败则返回默认名
*/
private static String extractFileNameFromUrl(String url) {
try {
if (url.contains("/")) {
String fileName = url.substring(url.lastIndexOf("/") + 1);
// 如果文件名包含参数,截取?之前的部分
if (fileName.contains("?")) {
fileName = fileName.substring(0, fileName.indexOf("?"));
}
// 如果提取的文件名有效,直接返回
if (fileName.contains(".")) {
return fileName;
}
}
} catch (Exception e) {
log.warn("提取文件名失败,使用默认文件名", e);
}
// 默认文件名
return "upload_" + System.currentTimeMillis() + ".png";
}
public static void main(String[] args) {
WechatPayConfigDto dto = new WechatPayConfigDto()
.setMerchantId("1643779408")
.setApiV3Key("a92baac5eb7a36ed8ec198113e769a03")
.setSerialNumber("4DE9BAC2EA584C3F274F694C9753CA814C4E9BF4")
.setPublicKey("""
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtbeWXEEjBaYtw2OyM+SC
aCEMbryRXi4duKxx3vYG4rUVix+d5/Jz7Khev4Upml9zC+Xxvv/G9bHWAUyolzqD
wefahGurIxr43r4GJVnQ4i5G6BbBVw5d4Vuz0y/9Zd14zmc/EmBpT0Ml26H7tOZl
n1LSbQ4xNFkrRKrNEcExBLxkCd+K5K2TREZznywIi0izbHImvuzM8IneuR51FiqK
pdFnAjTwb126EIj6ECkL6KLCl8RWqpfiX8SFiolSQLs1/w79O0sIUk96X2zWpnoW
rTDFatPif/VEKl3y2dTlxxDxoZtVi48yTDW00OMzVl5D67oX3FVK0KsjHJSCfGlZ
6wIDAQAB
-----END PUBLIC KEY-----""")
.setPrivateKey("""
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDqnAZhTxT572fo
6wvSr8Rt0vRXg+EFKC6UvUiNE24oocQU5fjedX9KL/+fmoqay/xqIxvxvCNFTs4J
zlMqavSl6bMWCpjvf/Ry82JmN1v2kJEO4lgP8BsEiqlUpObCH8BMAVUOn1j+9q4Q
uZJJcbtRvec2fNweDM8EJp4B7RlUdDbHm86lfcDVp8iini7VjDp6D7aHT+C8A8OT
ugxQIquDec778wVd9r2Sv3+t6rAzFs+n+Zu++2xtFEPhO5N0wjrLHaukl+9crU+1
lktjDzcPd07SwGZ+A+3BTmW3UCramI3506e/3MWBECB7ge+gM4URAV0nJJCLH/Im
WgEvPMr5AgMBAAECggEBAKv+wraoMWqiVv1tA/froAgbtcJLDranJK8qrXuvmPz0
yzm+91qvrSgIVFEADUk67swo/R2Vng37nhWWS2Y3jy/rSr2H+2Lp3Z5ATA0/3I3A
onfU/FaC4mvL9CP32KzMdj/CYkccDzSsSCQ+x75MQNXGcTGDDCSDo2kZnpEu73j3
aqvO1jbqTGWigRfjOIaIhStjQIT8nEm/3mJ4f5dM9M6FMz33mhax8EahSgvdahYB
t45iaGOWw81OJhmry47EvpwjXBl7jtO2HX3LiLbq5Ebcwu1zqDz5NM7ttnnGAqWC
6y7JN5Vt4wPYrCydiUDe7dj0looffr2yw6MkNfYjLGECgYEA+FAvbEInQEi9YguS
CQtLHngqvYeai66tvyykog9o38KHnPGx2Myf+rn/Hcp7KNRfjd5G34CCNg7KLnrx
YIYh6+2bY3jirzdYUxuNKGbvM4gky/6M/P9zHF/uALKOE02yArdqemf4UxUvrYCc
JdXsAMqvbpdvW1aGgNRB32YCkG0CgYEA8d89vawsCjNCEUh0VWTMoBLFoex3qBMZ
rfzYQeBo6bDCRlAlUVzl+ouBUxSYxP/U8rzeNaRzGUwRLmlGMjyIr58FBlHsg2cR
DlsX3HVCUjpS6sgPXOqakdiLfhMcHZAspislSyVfeS3TbUWiA45+5PuNUq+EZYwl
ESsB1+yfRT0CgYEA0Ct49ksnWM8iZbXJgeeD3FFlk2rBd2TDqEem5W4Bv8T3p+0/
6b7yR2HyrGj5gys3yFmWFP1JLESN3xWWkhMhEQcrg+LuN3Iwi8vHNR3GXu892f7W
96q4OAt8Hf2S+j/igkB99YyANDbIt63gOh/zMF67X/14j5wkOpC3gK+maqkCgYEA
s7nIrPoUt3ejLiiCmTmPe5q3VDzcJP4cZNau8zSHgK6hjZHcSPsYwPWMoWl6o1fe
qoiBLacHB9MoKS58xLOKdcVZ/Ho/ntylJd+2eVCAeY1xM5h5IfgJ5znbXVFh4O3S
357L1Wzt5qOQqW/GlZH65LevKbPWU4axvHISqpnfN5kCgYEAqiqLuAPu84VSsqsE
GFh25t+1f0JY1sNfilE3/t9AdQeeCFv/5z9KB1kMt3a5ZFeVonsFIvCyaOJjhSkj
4HCB94vWS7NuN5G9r874lMaPbZYQGwrcVaf265tN7cYYr3gUx1qB6+u+fh/kcft1
BBmTzhb0zp5k8ngwAkA1g/LK204=
-----END PRIVATE KEY-----""")
.setPublicKeyId("PUB_KEY_ID_0116437794082025111000382377001000")
.setDomain("https://api.mch.weixin.qq.com");
// String string = uploadImage(dto, "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png");
// log.info("图片上传成功:{}", string);
WechatEntryReqDto reqDto = new WechatEntryReqDto();
System.out.println(JSONObject.toJSONString(reqDto, JSONWriter.Feature.IgnoreEmpty));
}
}

View File

@@ -0,0 +1,11 @@
package com.czg.wechat;
/**
* @author yjjie
* @date 2025/12/26 09:15
*/
public class WechatPayManager {
public static void main(String[] args) {
}
}

View File

@@ -0,0 +1,49 @@
package com.czg.wechat.dto.config;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author yjjie
* @date 2025/12/26 09:21
*/
@Data
@Accessors(chain = true)
public class WechatPayConfigDto {
/**
* 商户号
*/
private String merchantId;
/**
* Api V3密钥
*/
private String apiV3Key;
/**
* 商户证书序列号
*/
private String serialNumber;
/**
* 商户私钥
*/
private String privateKey;
/**
* 商户公钥
*/
private String publicKey;
/**
* 商户公钥 ID
*/
private String publicKeyId;
/**
* 微信支付域名
* <a href="https://api.mch.weixin.qq.com"></a>
*/
private String domain;
}

View File

@@ -0,0 +1,51 @@
package com.czg.wechat.dto.req.entry;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 微信进件-补充信息
*
* @author yjjie
* @date 2025/12/26 13:43
*/
@Data
@Accessors(chain = true)
public class WechatEntryAdditionReqDto {
/**
* 【选填】
* 法定代表人开户承诺函
* 模板下载地址 <a href="https://kf.qq.com/faq/191018yUFjEj191018Vfmaei.html">...</a>
* 通过图片上传完成后 MediaID
*/
@JSONField(name = "legal_person_commitment")
private String legalPersonCommitment;
/**
* 【选填】
* 法定代表人开户意愿视频
* 通过视频上传完成后 MediaID
*/
@JSONField(name = "legal_person_video")
private String legalPersonVideo;
/**
* 【选填】
* 补充材料
* 最多可上传5张照片
* 通过图片上传完成后 MediaID
*/
@JSONField(name = "business_addition_pics")
private List<String> businessAdditionPics;
/**
* 【选填】
* 补充说明 512字以内
*/
@JSONField(name = "business_addition_msg")
private String businessAdditionMsg;
}

View File

@@ -0,0 +1,75 @@
package com.czg.wechat.dto.req.entry;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信进件-银行账号
*
* @author yjjie
* @date 2025/12/26 13:42
*/
@Data
@Accessors(chain = true)
public class WechatEntryBankAccountReqDto {
/**
* 【必填】
* 账户类型
* 1、若主体为企业/政府机关/事业单位/社会组织,可填写:对公银行账户;
* 2、若主体为个体户可选择填写对公银行账户或经营者个人银行卡
* 可选取值 BANK_ACCOUNT_TYPE_CORPORATE: 对公银行账户 BANK_ACCOUNT_TYPE_PERSONAL: 经营者个人银行卡
*/
@JSONField(name = "bank_account_type")
private String bankAccountType;
/**
* 【必填】
* 开户名称
* 1、选择“经营者个人银行卡”时开户名称必须与“经营者证件姓名”一致
* 2、选择“对公银行账户”时开户名称必须与营业执照上的“商户名称”一致
* 3、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
* <a href="https://pay.weixin.qq.com/doc/v3/partner/4013059044">...</a>
*/
@JSONField(name = "account_name")
private String accountName;
/**
* 【必填】
* 开户银行
* 对私银行调用查询支持个人业务的银行列表API
* 对公银行调用查询支持对公业务的银行列表API
*/
@JSONField(name = "account_bank")
private String accountBank;
/**
* 【选填】
* 开户银行银行号
* 1、根据开户银行查询接口中的“是否需要填写支行”判断是否需要填写。如为其他银行开户银行全称含支行和开户银行联行号二选一
* 2、详细需调用查询支行列表API查看查询结果。 <a href="https://pay.weixin.qq.com/doc/v3/partner/4012697673">...</a>
*/
@JSONField(name = "bank_branch_id")
private String bankBranchId;
/**
* 【选填】
* 开户银行全称(含支行)
* 1、根据开户银行查询接口中的“是否需要填写支行”判断是否需要填写。如为其他银行开户银行全称含支行和开户银行联行号二选一
* 2、详细需调用查询支行列表API查看查询结果。 <a href="https://pay.weixin.qq.com/doc/v3/partner/4012697673">...</a>
*/
@JSONField(name = "bank_name")
private String bankName;
/**
* 【必填】
* 开户银行账号
* 1、选择“经营者个人银行卡”时开户账号为经营者个人银行卡号
* 2、选择“对公银行账户”时开户账号为对公银行账号
* 3、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
* <a href="https://pay.weixin.qq.com/doc/v3/partner/4013059044">...</a>
*/
@JSONField(name = "account_number")
private String accountNumber;
}

View File

@@ -0,0 +1,139 @@
package com.czg.wechat.dto.req.entry;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 进件 联系人信息
*
* @author yjjie
* @date 2025/12/26 13:38
*/
@Data
@Accessors(chain = true)
public class WechatEntryContactReqDto {
/**
* 【必填】
* 超级管理员类型
* 主体为“个体工商户/企业/政府机关/事业单位/社会组织”可选择LEGAL经营者/法定代表人SUPER经办人 。(经办人:经商户授权办理微信支付业务的人员)。
* 可选取值
* LEGAL: 经营者/法定代表人
* SUPER: 经办人
*/
@JSONField(name = "contact_type")
private String contactType;
/**
* 【必填】
* 超级管理员姓名
* 1、长度为2-100个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符。
* 该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "contact_name")
private String contactName;
/**
* 【选填】
* 超级管理员证件类型 当超级管理员类型是经办人时,请上传超级管理员证件类型。
* 可选取值
* IDENTIFICATION_TYPE_IDCARD: 中国大陆居民-身份证
* IDENTIFICATION_TYPE_OVERSEA_PASSPORT: 其他国家或地区居民-护照
* IDENTIFICATION_TYPE_HONGKONG_PASSPORT: 中国香港居民-来往内地通行证
* IDENTIFICATION_TYPE_MACAO_PASSPORT: 中国澳门居民-来往内地通行证
* IDENTIFICATION_TYPE_TAIWAN_PASSPORT: 中国台湾居民-来往大陆通行证
* IDENTIFICATION_TYPE_FOREIGN_RESIDENT: 外国人居留证
* IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT: 港澳居民居住证
* IDENTIFICATION_TYPE_TAIWAN_RESIDENT: 台湾居民居住证
*/
@JSONField(name = "contact_id_type")
private String contactIdType;
/**
* 【选填】
* 超级管理员身份证件号码
* 1、当超级管理员类型是经办人时请上传超级管理员证件号码
* 2、可传身份证、来往内地通行证、来往大陆通行证、护照等证件号码号码规范如下
* 身份证限中国大陆居民17位数字+1位数字|X
* 护照限境外人士4-15位 数字|字母|连字符;
* 中国香港居民--来往内地通行证H/h开头+8或10位数字/字母;
* 中国澳门居民--来往内地通行证M/m开头+8或10位数字/字母;
* 中国台湾居民--来往大陆通行证8位数字或10位数字
* 外国人居留证15位 数字|字母;
* 台湾居民居住证/港澳居民居住证17位数字+1位数字|X
* 3、超级管理员签约时校验微信号绑定的银行卡实名信息是否与该证件号码一致
* 4、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "contact_id_number")
private String contactIdNumber;
/**
* 【选填】
* 超级管理员证件正面照片
* 1、当超级管理员类型是经办人时请上传超级管理员证件的正面照片
* 2、若证件类型为身份证请上传人像面照片
* 3、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 4、请上传彩色照片或彩色扫描件或复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 5、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "contact_id_doc_copy")
private String contactIdDocCopy;
/**
* 【选填】
* 超级管理员证件反面照片
* 1、当超级管理员类型是经办人时请上传超级管理员证件的反面照片
* 2、若证件类型为护照无需上传反面照片
* 3、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 4、请上传彩色照片或彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 5、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "contact_id_doc_copy_back")
private String contactIdDocCopyBack;
/**
* 【选填】
* 超级管理员证件有效期开始时间
* 1、当超级管理员类型是经办人时请上传证件有效期开始时间
* 2、请按照示例值填写日期格式应满足合法的YYYY-MM-DD格式
* 3、开始时间不能小于1900-01-01开始时间不能大于等于当前日期。
*/
@JSONField(name = "contact_period_begin")
private String contactPeriodBegin;
/**
* 【选填】
* 超级管理员证件有效期截止时间
* 1、当超级管理员类型是经办人时请上传证件有效期结束时间
* 2、请按照示例值填写日期格式应满足合法的YYYY-MM-DD格式若证件有效期为长期请填写长期
* 3、结束时间大于开始时间。
*/
@JSONField(name = "contact_period_end")
private String contactPeriodEnd;
/**
* 【必填】
* 联系手机
* 1、前后不能有空格、制表符、换行符
* 2、需满足以下任一条件
* 11位数字的手机号码
* 5-20位数字、连字符“-”、加号“+”;
* 3、用于接收微信支付的重要管理信息及日常操作验证码
* 4、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "mobile_phone")
private String mobilePhone;
/**
* 【必填】
* 联系邮箱
* 1、用于接收微信支付的开户邮件及日常业务通知
* 2、需要带@,遵循邮箱格式校验 该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "contact_email")
private String contactEmail;
}

View File

@@ -0,0 +1,69 @@
package com.czg.wechat.dto.req.entry;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.wechat.dto.req.entry.business.WechatEntryBusinessReqDto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信进件请求参数
* 参考地址 <a href="https://pay.weixin.qq.com/doc/v3/partner/4012719997">...</a>
* @author yjjie
* @date 2025/12/26 13:36
*/
@Data
@Accessors(chain = true)
public class WechatEntryReqDto {
/**
* 【必填】
* 业务申请编号
*/
@JSONField(name = "business_code")
private String businessCode;
/**
* 【必填】
* 超级管理员信息
*/
@JSONField(name = "contact_info")
private WechatEntryContactReqDto contactInfo;
/**
* 【必填】
* 主体资料
*/
@JSONField(name = "subject_info")
private WechatEntrySubjectReqDto subjectInfo;
/**
* 【必填】
* 经营资料
* 商家的经营业务信息、售卖商品/提供服务场景信息
*/
@JSONField(name = "business_info")
private WechatEntryBusinessReqDto businessInfo;
/**
* 【必填】
* 结算规则
* 请填写商家的结算费率规则、特殊资质等信息
*/
@JSONField(name = "settlement_info")
private WechatEntrySettleReqDto settlementInfo;
/**
* 【必填】
* 结算银行账户
*/
@JSONField(name = "bank_account_info")
private WechatEntryBankAccountReqDto bankAccountInfo;
/**
* 【选填】
* 补充材料
* 根据实际审核情况,会额外要求商家提供指定的补充资料
*/
@JSONField(name = "addition_info")
private WechatEntryAdditionReqDto additionInfo;
}

View File

@@ -0,0 +1,91 @@
package com.czg.wechat.dto.req.entry;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件 结算信息
* @author yjjie
* @date 2025/12/26 13:38
*/
@Data
@Accessors(chain = true)
public class WechatEntrySettleReqDto {
/**
* 【必填】
* 入驻结算规则ID
* 请选择结算规则ID详细参见费率结算规则对照表
* <a href="https://kf.qq.com/faq/220228IJb2UV220228uEjU3Q.html">...</a>
*/
@JSONField(name = "settlement_id")
private String settlementId;
/**
* 【必填】
* 所属行业
* <a href="https://kf.qq.com/faq/220228IJb2UV220228uEjU3Q.html">...</a>
*/
@JSONField(name = "qualification_type")
private String qualificationType;
/**
* 【选填】
* 特殊资质图片
* 1、仅当商户选择了必需提交特殊资质的行业时需要提供该项资料若商户选择了无需特殊资质的行业或未选择行业时无需提交该项资料详情查看《费率结算规则对照表》
* 2、最多可上传5张照片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "qualifications")
private List<String> qualifications;
/**
* 【选填】
* 优惠费率活动ID
* 如果商户有意向报名优惠费率活动,该字段【必填】。详细参见《优惠费率活动对照表》
* <a href="https://pay.weixin.qq.com/doc/v3/partner/4012082816">...</a>
*/
@JSONField(name = "activities_id")
private String activitiesId;
/**
* 【选填】
* 优惠费率活动值
* 根据优惠费率活动规则由合作伙伴自定义填写支持两个小数点需在优惠费率活动ID指定费率范围内
* 12023年7月17日-9月17日各合作伙伴平台可选择只传入“活动费率值”或分别传入“信用卡优惠活动费率值” 与 “非信用卡优惠活动费率值”,只传入“活动费率值”的情况下,平台将协助将申请单中的 “优惠活动费率值” 回填入新增的 “信用卡优惠活动费率值” 与 “非信用卡优惠活动费率值”中
* 22023年9月18日起平台将不再提供如上兼容能力届时仅能分别传入“信用卡优惠活动费率值” 与 “非信用卡优惠活动费率值”,否则接口将会报错。为避免影响正常进件,请在兼容期间完成相关调整。
*/
@JSONField(name = "activities_rate")
private String activitiesRate;
/**
* 【选填】
* 优惠费率活动补充材料
* 1、根据所选优惠费率活动提供相关材料详细参见《优惠费率活动对照表》<a href="https://pay.weixin.qq.com/doc/v3/partner/4012082816">...</a>
* 2、最多可上传5张照片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "activities_additions")
private List<String> activitiesAdditions;
/**
* 【选填】
* 非信用卡活动费率值
* 用户支付方式为借记卡时收取的手续费费率:
* 1、若填写了优惠费率活动ID则该字段【必填】
* 2、仅能填入2位以内小数且在优惠费率活动ID指定费率范围内。
*/
@JSONField(name = "debit_activities_rate")
private String debitActivitiesRate;
/**
* 【选填】
* 信用卡活动费率值
* 用户支付方式为信用卡时收取的手续费费率:
* 1、若填写了优惠费率活动ID则该字段【必填】
* 2、仅能填入2位以内小数且在优惠费率活动ID指定费率范围内。
*/
@JSONField(name = "credit_activities_rate")
private String creditActivitiesRate;
}

View File

@@ -0,0 +1,103 @@
package com.czg.wechat.dto.req.entry;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.wechat.dto.req.entry.business.*;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件 主体资料
* @author yjjie
* @date 2025/12/26 13:40
*/
@Data
@Accessors(chain = true)
public class WechatEntrySubjectReqDto {
/**
* 【必填】
* 主体类型 主体类型需与营业执照/登记证书上一致,可参考选择主体指引。<a href="https://kf.qq.com/faq/180910IBZVnQ180910naQ77b.html">...</a>
* 可选取值
* SUBJECT_TYPE_INDIVIDUAL: (个体户)营业执照上的主体类型一般为个体户、个体工商户、个体经营
* SUBJECT_TYPE_ENTERPRISE: (企业)营业执照上的主体类型一般为有限公司、有限责任公司
* SUBJECT_TYPE_GOVERNMENT: (政府机关)包括各级、各类政府机关,如机关党委、税务、民政、人社、工商、商务、市监等
* SUBJECT_TYPE_INSTITUTIONS: (事业单位)包括国内各类事业单位,如:医疗、教育、学校等单位
* SUBJECT_TYPE_OTHERS:(社会组织) 包括社会团体、民办非企业、基金会、基层群众性自治组织、农村集体经济组织等组织
*/
@JSONField(name = "subject_type")
private String subjectType;
/**
* 【选填】
* 是否是金融机构
* 【是否是金融机构】 【选填】,请根据申请主体的实际情况填写,可参考选择金融机构指引:
* 1、若商户主体是金融机构则填写true
* 2、若商户主体不是金融机构则填写false。
* 若未传入将默认填写false。
*/
@JSONField(name = "finance_institution")
private Boolean financeInstitution;
/**
* 【必填】
* 营业执照 当前不允许小微注册,所以【必填】
* 1、主体为个体户/企业,【必填】;
* 2、请上传“营业执照”需年检章齐全当年注册除外
*/
@JSONField(name = "business_license_info")
private WechatEntryLicenseReqDto businessLicenseInfo;
/**
* 【选填】
* 登记证书 主体为政府机关/事业单位/其他组织时,【必填】。
*/
@JSONField(name = "certificate_info")
private WechatEntryCertificateReqDto certificateInfo;
/**
* 【选填】
* 单位证明函照片
* 1、主体类型为政府机关、事业单位选传
* 1若上传则审核通过后即可签约无需汇款验证
* 2若未上传则审核通过后需汇款验证。
* 2、主体为个体户、企业、其他组织等不需要上传本字段
* 3、请参照示例图打印单位证明函全部信息需打印不支持手写商户信息并加盖公章 <a href="https://kf.qq.com/faq/200114u2y2yQ200114uEz26z.html">...</a>
* 4、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "certificate_letter_copy")
private String certificateLetterCopy;
/**
* 【选填】
* 金融机构许可证信息 当主体是金融机构时,【必填】。
*/
@JSONField(name = "finance_institution_info")
private WechatEntryFinanceInstitutionReqDto financeInstitutionInfo;
/**
* 【必填】
* 经营者/法定代表人身份证件
* 1、个体户请上传经营者的身份证件
* 2、企业/社会组织:请上传法定代表人的身份证件;
* 3、政府机关/事业单位:请上传法定代表人/经办人的身份证件。
*/
@JSONField(name = "identity_info")
private WechatEntryIdentityReqDto identityInfo;
/**
* 【选填】
* 最终受益人信息列表(UBO)
* 1、主体类型个体户/社会组织/政府机关/事业单位时,无需填写
* 2、主体类型为企业时按照下述要求填写
* 1若经营者/法定代表人不是最终受益所有人则需提填写受益所有人信息最多上传4个。
* 2若经营者/法定代表人是最终受益所有人之一可在此填写其他受益所有人信息最多上传3个。
* 根据国家相关法律法规,需要提供公司受益所有人信息,受益所有人需符合至少以下条件之一:
* ▪直接或者间接拥有超过25%公司股权或者表决权的自然人。
* ▪️通过人事、财务等其他方式对公司进行控制的自然人。
* ▪️公司的高级管理人员,包括公司的经理、副经理、财务负责人、上市公司董事会秘书和公司章程规定的其他人员。
*/
@JSONField(name = "ubo_info_list")
private List<WechatEntryUboInfoReqDto> uboInfoList;
}

View File

@@ -0,0 +1,50 @@
package com.czg.wechat.dto.req.entry.business;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.wechat.dto.req.entry.business.sales.WechatEntrySalesInfoReqDto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信进件 商户信息 经营资料
*
* @author yjjie
* @date 2025/12/26 13:41
*/
@Data
@Accessors(chain = true)
public class WechatEntryBusinessReqDto {
/**
* 【必填】
* 商户简称 在支付完成页向买家展示,需与微信经营类目相关
* 1、请输入1-64个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式
* 6、简称要求
* 1不支持单纯以人名来命名若为个体户经营可用“个体户+经营者名称”或“经营者名称+业务”命名,如“个体户张三”或“张三餐饮店”;
* 2不支持无实际意义的文案如“XX特约商户”、“800”、“XX客服电话XXX”。
*/
@JSONField(name = "merchant_shortname")
private String merchantShortname;
/**
* 【必填】
* 客服电话 将在交易记录中向买家展示,请确保电话畅通以便平台回拨确认
* 1、前后不能有空格、制表符、换行符
* 2、需满足以下任一条件
* 11位数字的手机号码
* 5-20位数字、连字符“-”、加号“+”。
*/
@JSONField(name = "service_phone")
private String servicePhone;
/**
* 【必填】
* 经营场景
*/
@JSONField(name = "sales_info")
private WechatEntrySalesInfoReqDto salesInfo;
}

View File

@@ -0,0 +1,111 @@
package com.czg.wechat.dto.req.entry.business;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 登记证书
* @author yjjie
* @date 2025/12/26 15:07
*/
@Data
@Accessors(chain = true)
public class WechatEntryCertificateReqDto {
/**
* 【必填】
* 登记证书照片
* 1、照片应正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 2、上传彩色照片、彩色扫描件复印件需加盖公章鲜章
* 3、水印仅限于微信支付业务相关
* 4、指引与示例可参考【指引文档】
* 5、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "cert_copy")
private String certCopy;
/**
* 【必填】
* 登记证书类型
* 1、主体为“政府机关/事业单位/社会组织”时,请上传登记证书类型;
* 2、主体为“个体工商户/企业”时,不填;
* 当主体为事业单位时,选择此枚举值:
* CERTIFICATE_TYPE_2388事业单位法人证书
* 当主体为政府机关,选择此枚举值:
* CERTIFICATE_TYPE_2389统一社会信用代码证书
* 当主体为社会组织,选择以下枚举值之一:
* CERTIFICATE_TYPE_2389统一社会信用代码证书
* CERTIFICATE_TYPE_2394社会团体法人登记证书
* CERTIFICATE_TYPE_2395民办非企业单位登记证书
* CERTIFICATE_TYPE_2396基金会法人登记证书
* CERTIFICATE_TYPE_2520执业许可证/执业证
* CERTIFICATE_TYPE_2521基层群众性自治组织特别法人统一社会信用代码证
* CERTIFICATE_TYPE_2522农村集体经济组织登记证
* CERTIFICATE_TYPE_2399宗教活动场所登记证
* CERTIFICATE_TYPE_2400政府部门下发的其他有效证明文件
*/
@JSONField(name = "cert_type")
private String certType;
/**
* 【必填】
* 证书号 请输入与所选证书类型相匹配且符合国家标准规范的证书号其中除政府证明文件外需满足18位阿拉伯数字或大写英文字母不得包含英文字母I/O/Z/S/V
*/
@JSONField(name = "cert_number")
private String certNumber;
/**
* 【必填】
* 商户名称 请填写登记证书上的商户名称
* 1、长度为2-128个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式。
*/
@JSONField(name = "merchant_name")
private String merchantName;
/**
* 【必填】
* 注册地址 请填写登记证书的注册地址
* 1、长度为4-128个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式。
*/
@JSONField(name = "company_address")
private String companyAddress;
/**
* 【必填】
* 法定代表人 请填写登记证书上的法定代表人姓名
* 1、长度为2-100个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符。
*/
@JSONField(name = "legal_person")
private String legalPerson;
/**
* 【选填】
* 有效期限开始日期 建议填写营业执照的有效期限开始时间,若该字段未填写,系统将会查询国家工商信息填入。需注意若工商信息查询不到,则会被审核驳回。
* 1、日期格式应满足合法的YYYY-MM-DD格式
* 2、开始时间不能小于1900-01-01
* 3、开始时间不能大于等于当前日期。
*/
@JSONField(name = "period_begin")
private String periodBegin;
/**
* 【选填】
* 营业期限结束日期 建议填写营业执照的有效期限结束时间,若该字段未填写,系统将会查询国家工商信息填入。需注意若工商信息查询不到,则会被审核驳回。
* 1、日期格式应满足合法的YYYY-MM-DD格式或长期
* 2、结束时间需大于开始时间。
*/
@JSONField(name = "period_end")
private String periodEnd;
}

View File

@@ -0,0 +1,42 @@
package com.czg.wechat.dto.req.entry.business;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 金融机构许可证信息
* @author yjjie
* @date 2025/12/26 15:21
*/
@Data
@Accessors(chain = true)
public class WechatEntryFinanceInstitutionReqDto {
/**
* 【必填】
* 金融机构类型 金融机构类型需与营业执照/登记证书上一致,可参考选择金融机构指引。
* BANK_AGENT银行业, 适用于商业银行、政策性银行、农村合作银行、村镇银行、开发性金融机构等
* PAYMENT_AGENT支付机构, 适用于非银行类支付机构
* INSURANCE保险业, 适用于保险、保险中介、保险代理、保险经纪等保险类业务
* TRADE_AND_SETTLE交易及结算类金融机构, 适用于交易所、登记结算类机构、银行卡清算机构、资金清算中心等
* OTHER其他金融机构, 适用于财务公司、信托公司、金融资产管理公司、金融租赁公司、汽车金融公司、贷款公司、货币经纪公司、消费金融公司、证券业、金融控股公司、股票、期货、货币兑换、小额贷款公司、金融资产管理、担保公司、商业保理公司、典当行、融资租赁公司、财经咨询等其他金融业务
*/
@JSONField(name = "finance_type")
private String financeType;
/**
* 必填
* 金融机构许可证图片
* 1、照片应正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 2、上传彩色照片、彩色扫描件复印件需加盖公章鲜章
* 3、水印仅限于微信支付业务相关
* 4、根据所属金融机构类型的许可证要求提供详情查看金融机构指引 <a href="https://kf.qq.com/faq/220215IrMRZ3220215n6buiU.html">...</a>
* 5、请提供为“申请商家主体”所属的许可证可授权使用总公司/分公司的特殊资质;
* 6、最多可上传5张照片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "finance_license_pics")
private List<String> financeLicensePics;
}

View File

@@ -0,0 +1,72 @@
package com.czg.wechat.dto.req.entry.business;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.wechat.dto.req.entry.id.WechatEntryIdCardReqDto;
import com.czg.wechat.dto.req.entry.id.WechatEntryIdDocInfoReqDto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 经营者/法定代表人身份证件
* @author yjjie
* @date 2025/12/26 15:24
*/
@Data
@Accessors(chain = true)
public class WechatEntryIdentityReqDto {
/**
* 【选填】
* 证件持有人类型
* 1、主体类型为政府机关/事业单位时选传:
* 1若上传的是法定代表人证件则不需要上传该字段。
* 2若因政策保密等原因无法提供法定代表人证件时可上传经办人。 (经办人:经商户授权办理微信支付业务的人员,授权范围包括但不限于签约,入驻过程需完成账户验证)。
* 2、主体类型为小微/个人卖家/企业/个体户/社会组织时,默认为经营者/法定代表人,不需要上传该字段。
* LEGAL: 经营者/法定代表人
* SUPER: 经办人
*/
@JSONField(name = "id_holder_type")
private String idHolderType;
/**
* 【选填】
* 证件类型
* 1、当证件持有人类型为法定代表人时填写。其他情况无需上传
* 2、个体户/企业/事业单位/社会组织:可选择任一证件类型,政府机关仅支持中国大陆居民-身份证类型。
* 可选取值
* IDENTIFICATION_TYPE_IDCARD: 中国大陆居民-身份证
* IDENTIFICATION_TYPE_OVERSEA_PASSPORT: 其他国家或地区居民-护照
* IDENTIFICATION_TYPE_HONGKONG_PASSPORT: 中国香港居民-来往内地通行证
* IDENTIFICATION_TYPE_MACAO_PASSPORT: 中国澳门居民-来往内地通行证
* IDENTIFICATION_TYPE_TAIWAN_PASSPORT: 中国台湾居民-来往大陆通行证
* IDENTIFICATION_TYPE_FOREIGN_RESIDENT: 外国人居留证
* IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT: 港澳居民居住证
* IDENTIFICATION_TYPE_TAIWAN_RESIDENT: 台湾居民居住证
*/
@JSONField(name = "id_doc_type")
private String idDocType;
/**
* 【选填】
* 法定代表人说明函
* 1、当证件持有人类型为经办人时必须上传。其他情况无需上传
* 2、若因特殊情况无法提供法定代表人证件时请参照示例图打印法定代表人说明函全部信息需打印不支持手写商户信息并加盖公章 <a href="https://kf.qq.com/faq/220127aUzAju220127UfiuQr.html">...</a>
* 3、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "authorize_letter_copy")
private String authorizeLetterCopy;
/**
* 【选填】
* 身份证信息 当证件持有人类型为经营者/法定代表人且证件类型为“身份证”时填写。
*/
@JSONField(name = "id_card_info")
private WechatEntryIdCardReqDto idCardInfo;
/**
* 【选填】
* 其他类型证件信息 当证件持有人类型为经营者/法定代表人且证件类型不为“身份证”时填写。
*/
@JSONField(name = "id_doc_info")
private WechatEntryIdDocInfoReqDto idDocInfo;
}

View File

@@ -0,0 +1,90 @@
package com.czg.wechat.dto.req.entry.business;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 营业执照信息
* @author yjjie
* @date 2025/12/26 14:59
*/
@Data
@Accessors(chain = true)
public class WechatEntryLicenseReqDto {
/**
* 【必填】
* 营业执照照片
* 1、照片应正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 2、上传彩色照片、彩色扫描件复印件需加盖公章鲜章
* 3、水印仅限于微信支付业务相关
* 4、指引与示例可参考【指引文档】
* 5、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "license_copy")
private String licenseCopy;
/**
* 【必填】
* 注册号/统一社会信用代码
*/
@JSONField(name = "license_number")
private String licenseNumber;
/**
* 【必填】
* 商户名称
* 1、长度为2-128个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式
* 6、个体户证件为以下情况时按照个体户XXX命名XXX是营业执照经营人姓名营业执照登记名称为空、仅含数字、仅含特殊字符、“无”、“无字号”
* 7、个体户不能使用“企业”“公司”或“农民专业合作社”结尾。
*/
@JSONField(name = "merchant_name")
private String merchantName;
/**
* 【必填】
* 个体户经营者/法定代表人姓名 请填写营业执照的经营者/法定代表人姓名
* 1、长度为2-100个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符。
*/
@JSONField(name = "legal_person")
private String legalPerson;
/**
* 【选填】
* 注册地址 建议填写营业执照的注册地址,若该字段未填写,系统将会查询国家工商信息填入。需注意若工商信息查询不到,则会被审核驳回。
* 1、长度为4-128个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式。
*/
@JSONField(name = "license_address")
private String licenseAddress;
/**
* 【选填】
* 有效期限开始日期 建议填写营业执照的有效期限开始时间,若该字段未填写,系统将会查询国家工商信息填入。需注意若工商信息查询不到,则会被审核驳回。
* 1、日期格式应满足合法的YYYY-MM-DD格式
* 2、开始时间不能小于1900-01-01
* 3、开始时间不能大于等于当前日期。
*/
@JSONField(name = "period_begin")
private String periodBegin;
/**
* 【选填】
* 营业期限结束日期 建议填写营业执照的有效期限结束时间,若该字段未填写,系统将会查询国家工商信息填入。需注意若工商信息查询不到,则会被审核驳回。
* 1、日期格式应满足合法的YYYY-MM-DD格式或长期
* 2、结束时间需大于开始时间。
*/
@JSONField(name = "period_end")
private String periodEnd;
}

View File

@@ -0,0 +1,113 @@
package com.czg.wechat.dto.req.entry.business;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 最终受益人信息
* @author yjjie
* @date 2025/12/26 15:50
*/
@Data
@Accessors(chain = true)
public class WechatEntryUboInfoReqDto {
/**
* 【必填】
* 证件类型 请填写受益人的证件类型。枚举值:
* 可选取值
* IDENTIFICATION_TYPE_IDCARD: 中国大陆居民-身份证
* IDENTIFICATION_TYPE_OVERSEA_PASSPORT: 其他国家或地区居民-护照
* IDENTIFICATION_TYPE_HONGKONG_PASSPORT: 中国香港居民-来往内地通行证
* IDENTIFICATION_TYPE_MACAO_PASSPORT: 中国澳门居民-来往内地通行证
* IDENTIFICATION_TYPE_TAIWAN_PASSPORT: 中国台湾居民-来往大陆通行证
* IDENTIFICATION_TYPE_FOREIGN_RESIDENT: 外国人居留证
* IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT: 港澳居民居住证
* IDENTIFICATION_TYPE_TAIWAN_RESIDENT: 台湾居民居住证
*/
@JSONField(name = "ubo_id_doc_type")
private String uboIdDocType;
/**
* 必填
* 证件正面照片
* 1、请上传受益人证件的正面照片
* 2、若证件类型为身份证请上传人像面照片
* 3、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 4、请上传彩色照片or彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 5、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "ubo_id_doc_copy")
private String uboIdDocCopy;
/**
* 【选填】
* 证件反面照片
* 1、请上传受益人证件的反面照片
* 2、若证件类型为身份证请上传国徽面照片
* 3、若证件类型为护照无需上传反面照片
* 4、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 5、请上传彩色照片or彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 6、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "ubo_id_doc_copy_back")
private String uboIdDocCopyBack;
/**
* 必填
* 证件姓名
* 1、长度为2-100个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "ubo_id_doc_name")
private String uboIdDocName;
/**
* 必填
* 证件号码
* 1、证件号码为证件正反面中一致的号码
* 2、证件号码为18位或15位或港澳居民来往内地通行证为9位
* 3、证件号码为英文字母X或x或港澳居民来往内地通行证为英文字母X或x
* 4、证件号码为英文字母x或X或港澳居民来往内地通行证为英文字母x或X
* 5、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥
*/
@JSONField(name = "ubo_id_doc_number")
private String uboIdDocNumber;
/**
* 必填
* 证件居住地址
* 1、请按照身份证住址填写如广东省深圳市南山区xx路xx号xx室
* 2、长度为4-128个字符
* 3、前后不能有空格、制表符、换行符
* 4、不能仅含数字、特殊字符
* 5、仅能填写数字、英文字母、汉字及特殊字符
* 6、仅支持utf-8格式
* 7、 该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "ubo_id_doc_address")
private String uboIdDocAddress;
/**
* 必填
* 证件有效期开始时间
* 1、日期格式应满足合法的YYYY-MM-DD格式
* 2、开始时间不能小于1900-01-01
* 3、开始时间不能大于等于当前日期。
*/
@JSONField(name = "ubo_period_begin")
private String uboPeriodBegin;
/**
* 必填
* 证件有效期结束时间
* 1、日期格式应满足合法的YYYY-MM-DD格式或长期
* 2、结束时间需大于开始时间。
*/
@JSONField(name = "ubo_period_end")
private String uboPeriodEnd;
}

View File

@@ -0,0 +1,45 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件-经营资料-经营场景-App场景
* @author yjjie
* @date 2025/12/26 14:26
*/
@Data
@Accessors(chain = true)
public class WechatEntryAppInfoReqDto {
/**
* 【必填】
* App截图
* 1、请提供APP首页截图、尾页截图、应用内截图、支付页截图各1张
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "app_pics")
private List<String> appPics;
/**
* 【选填】
* 商家应用AppID
* 1、服务商应用AppID与商家应用AppID二选一【必填】
* 2、可填写与商家主体一致且已认证的应用AppID需是已认证的App
* 3、审核通过后系统将发起特约商家商户号与该AppID的绑定即配置为sub_appid服务商随后可在发起支付时选择传入该AppID以完成支付并获取sub_openid用于数据统计营销等业务场景。
*/
@JSONField(name = "app_sub_appid")
private String appSubAppid;
/**
* 【选填】
* 服务商应用AppID
* 1、服务商应用AppID与商家应用AppID二选一【必填】
* 2、可填写当前服务商商户号已绑定的应用AppID。
*/
@JSONField(name = "app_appid")
private String appAppid;
}

View File

@@ -0,0 +1,47 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件-经营资料-经营场景-小程序场景
* @author yjjie
* @date 2025/12/26 14:23
*/
@Data
@Accessors(chain = true)
public class WechatEntryMiniProgramReqDto {
/**
* 【选填】
* 服务商小程序AppID
* 1、服务商小程序AppID与商家小程序AppID二选一必填
* 2、可填写当前服务商商户号已绑定的小程序AppID。
*/
@JSONField(name = "mini_program_appid")
private String miniProgramAppid;
/**
* 【选填】
* 商家小程序AppID
* 1、服务商小程序AppID与商家小程序AppID二选一必填
* 2、请填写已认证的小程序AppID
* 3、完成进件后系统发起特约商户号与该AppID的绑定即配置为sub_appid可在发起支付时传入
* 1若AppID主体与商家主体/服务商主体一致,则直接完成绑定;
* 2若AppID主体与商家主体/服务商主体不一致则商户签约时显示《联合营运承诺函》并且AppID的管理员需登录公众平台确认绑定意愿。
*/
@JSONField(name = "mini_program_sub_appid")
private String miniProgramSubAppid;
/**
* 【选填】
* 小程序截图
* 1、请提供展示商品/服务的页面截图/设计稿最多5张若小程序未建设完善或未上线 请务必提供;
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "mini_program_pics")
private List<String> miniProgramPics;
}

View File

@@ -0,0 +1,45 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件-经营资料-经营场景-服务号或公众号景
* @author yjjie
* @date 2025/12/26 14:20
*/
@Data
@Accessors(chain = true)
public class WechatEntryMpInfoReqDto {
/**
* 【必填】
* 服务号或公众号页面截图
* 1、请提供展示商品/服务的页面截图/设计稿最多5张若服务号或公众号未建设完善或未上线请务必提供
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "mp_pics")
private List<String> mpPics;
/**
* 【选填】
* 商家服务号或公众号AppID
* 1、服务商服务号或公众号AppID、商家服务号或公众号AppID二选一【必填】
* 2、可填写与商家主体一致且已认证的服务号或公众号AppID需是已认证的服务号、政府或媒体类型的公众号
* 3、审核通过后系统将发起特约商家商户号与该AppID的绑定即配置为sub_appid服务商随后可在发起支付时选择传入该appid以完成支付并获取sub_openid用于数据统计营销等业务场景。
*/
@JSONField(name = "mp_sub_appid")
private String mpSubAppid;
/**
* 【选填】
* 服务商服务号或公众号AppID
* 1、服务商服务号或公众号AppID、商家服务号或公众号AppID二选一【必填】
* 2、可填写当前服务商商户号已绑定的服务号或公众号AppID。
*/
@JSONField(name = "mp_appid")
private String mpAppid;
}

View File

@@ -0,0 +1,87 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件-经营场景
* @author yjjie
* @date 2025/12/26 14:07
*/
@Data
@Accessors(chain = true)
public class WechatEntrySalesInfoReqDto {
/**
* 【必填】
* 经营场景类型
* 1、请勾选实际售卖商品/提供服务场景(至少一项),以便为你开通需要的支付权限;
* 2、建议只勾选目前必须的场景以便尽快通过入驻审核其他支付权限可在入驻后再根据实际需要发起申请
* 可选取值
* SALES_SCENES_STORE: 线下场所
* SALES_SCENES_MP: 服务号与公众号
* SALES_SCENES_MINI_PROGRAM: 小程序
* SALES_SCENES_WEB: 互联网网站
* SALES_SCENES_APP: App
* SALES_SCENES_WEWORK: 企业微信
*/
@JSONField(name = "sales_scenes_type")
private List<String> salesScenesType;
/**
* 【选填】
* 线下场所场景
* 1、审核通过后服务商可帮商户发起付款码支付、JSAPI支付
* 2、当"经营场景类型"选择"SALES_SCENES_STORE",该场景资料【必填】。
*/
@JSONField(name = "biz_store_info")
private WechatEntryStoreInfoReqDto bizStoreInfo;
/**
* 【选填】
* 服务号或公众号场景
* 1、审核通过后服务商可帮商家发起JSAPI支付
* 2、当"经营场景类型"选择"SALES_SCENES_MP",该场景资料【必填】。
*/
@JSONField(name = "mp_info")
private WechatEntryMpInfoReqDto mpInfo;
/**
* 【选填】
* 小程序场景
* 1、审核通过后服务商可帮商家发起JSAPI支付
* 2、当"经营场景类型"选择"SALES_SCENES_MINI_PROGRAM",该场景资料必填。
*/
@JSONField(name = "mini_program_info")
private WechatEntryMiniProgramReqDto miniProgramInfo;
/**
* 【选填】
* App场景
* 1、审核通过后服务商可帮商家发起App支付
* 2、当"经营场景类型"选择"SALES_SCENES_APP",该场景资料必填。
*/
@JSONField(name = "app_info")
private WechatEntryAppInfoReqDto appInfo;
/**
* 【选填】
* 互联网网站场景
* 1、审核通过后服务商可帮商家发起JSAPI支付
* 2、当"经营场景类型"选择"SALES_SCENES_WEB",该场景资料必填。
*/
@JSONField(name = "web_info")
private WechatEntryWebInfoReqDto webInfo;
/**
* 【选填】
* 企业微信场景
* 1、审核通过后服务商可帮商家发起JSAPI支付
* 2、当"经营场景类型"选择"SALES_SCENES_WEWORK",该场景资料必填。
*/
@JSONField(name = "wework_info")
private WechatEntryWeworkInfoReqDto weworkInfo;
}

View File

@@ -0,0 +1,78 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 进件-经营资料-经营场景-线下场所场景
* @author yjjie
* @date 2025/12/26 14:10
*/
@Data
@Accessors(chain = true)
public class WechatEntryStoreInfoReqDto {
/**
* 【必填】
* 线下场所名称 请填写门店名称
* 1、长度为1-50个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式。
*/
@JSONField(name = "biz_store_name")
private String bizStoreName;
/**
* 【必填】
* 线下场所省市编码
* 1、只能由数字组成
* 2、详细参见微信支付提供的省市对照表。 <a href="https://pay.weixin.qq.com/doc/v3/partner/4012082815">...</a>
*/
@JSONField(name = "biz_address_code")
private String bizAddressCode;
/**
* 【必填】
* 线下场所地址 请填写详细的经营场所信息,如有多个场所,选择一个主要场所填写即可。
* 1、长度为4-512个字符
* 2、前后不能有空格、制表符、换行符
* 3、不能仅含数字、特殊字符
* 4、仅能填写数字、英文字母、汉字及特殊字符
* 5、仅支持utf-8格式
*/
@JSONField(name = "biz_store_address")
private String bizStoreAddress;
/**
* 【必填】
* 线下场所门头照片
* 1、请上传门头正面照片要求门店招牌、门框完整、清晰、可辨识若为停车场等无固定门头照片的经营场所可上传岗亭/出入闸口。具体参考【指引文档】;
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "store_entrance_pic")
private List<String> storeEntrancePic;
/**
* 【必填】
* 线下场所内部照片
* 1、请上传门店内部环境照片可辨识经营内容。若为停车场等无固定门头的经营场所可上传停车场内部照片。具体参考【指引文档】
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "indoor_pic")
private List<String> indoorPic;
/**
* 【选填】
* 线下场所对应的商家AppID
* 1、可填写与商家主体一致且已认证的服务号或公众号、小程序、APP的AppID其中服务号或公众号AppID需是已认证的服务号、政府或媒体类型的公众号
* 2、审核通过后系统将额外为商家开通付款码支付、JSAPI支付的自有交易权限并完成商家商户号与该AppID的绑定。
*/
@JSONField(name = "biz_sub_appid")
private String bizSubAppid;
}

View File

@@ -0,0 +1,44 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 进件-经营资料-经营场景-互联网网站场景
* @author yjjie
* @date 2025/12/26 14:29
*/
@Data
@Accessors(chain = true)
public class WechatEntryWebInfoReqDto {
/**
* 【必填】
* 互联网网站域名
* 1、如为PC端商城、智能终端等场景可上传官网链接
* 2、网站域名需ICP备案若备案主体与申请主体不同请上传加盖公章的网站授权函。
*/
@JSONField(name = "domain")
private String domain;
/**
* 【必填】
* 网站授权函
* 1、若备案主体与申请主体不同请务必上传加盖公章的网站授权函.doc <a href="https://gtimg.wechatpay.cn/resource/xres/mmpaydoc/static/attachment/bb55b16e3825a5952a531d55fba0f382/%E7%BD%91%E7%AB%99%E6%8E%88%E6%9D%83%E5%87%BD.doc">...</a>
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "web_authorisation")
private String webAuthorisation;
/**
* 【选填】
* 互联网网站对应的商家AppID
* 1、可填写已认证的服务号或公众号、小程序、APP的AppID其中服务号或公众号AppID需是已认证的服务号、政府或媒体类型的公众号
* 2、完成进件后系统发起特约商户号与该AppID的绑定即配置为sub_appid可在发起支付时传入
* 1若APPID主体与商家主体一致则直接完成绑定
* 2若APPID主体与商家主体不一致则商户签约时显示《联合营运承诺函》并且 AppID的管理员需登录公众平台确认绑定意愿 暂不支持绑定异主体的应用APPID
*/
@JSONField(name = "web_appid")
private String webAppid;
}

View File

@@ -0,0 +1,33 @@
package com.czg.wechat.dto.req.entry.business.sales;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 进件-经营资料-经营场景-企业微信场景
* @author yjjie
* @date 2025/12/26 14:32
*/
@Data
@Accessors(chain = true)
public class WechatEntryWeworkInfoReqDto {
/**
* 【必填】
* 商家企业微信CorpID
* 1、可填写与商家主体一致且已认证的企业微信CorpID
* 2、审核通过后系统将为商家开通企业微信专区的自有交易权限并完成商家商户号与该AppID的绑定商家可自行发起交易。
*/
@JSONField(name = "sub_corp_id")
private String subCorpId;
/**
* 必填
* 企业微信页面截图
* 1、最多可上传5张照片
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "wework_pics")
private String[] weworkPics;
}

View File

@@ -0,0 +1,96 @@
package com.czg.wechat.dto.req.entry.id;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 身份证信息
* @author yjjie
* @date 2025/12/26 15:29
*/
@Data
@Accessors(chain = true)
public class WechatEntryIdCardReqDto {
/**
* 【必填】
* 身份证人像面照片
* 1、请上传个体户经营者/法定代表人的身份证人像面照片;
* 2、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 3、请上传彩色照片or彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 4、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "id_card_copy")
private String idCardCopy;
/**
* 【必填】
* 身份证国徽面照片
* 、请上传个体户经营者/法定代表人的身份证国徽面照片;
* 2、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 3、请上传彩色照片or彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 4、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "id_card_national")
private String idCardNational;
/**
* 【必填】
* 身份证姓名
* 1、请填写个体户经营者/法定代表人对应身份证的姓名;
* 2、长度为2-100个字符
* 3、前后不能有空格、制表符、换行符
* 4、不能仅含数字、特殊字符
* 5、仅能填写数字、英文字母、汉字及特殊字符
* 6、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
* <a href="https://pay.weixin.qq.com/doc/v3/partner/4013059044">加密</a>
*/
@JSONField(name = "id_card_name")
private String idCardName;
/**
* 必填
* 身份证号码
* 1、请填写个体户经营者/法定代表人对应身份证的号码;
* 2、17位数字+1位数字|X 该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
* <a href="https://pay.weixin.qq.com/doc/v3/partner/4013059044">加密</a>
*/
@JSONField(name = "id_card_number")
private String idCardNumber;
/**
* 【选填】
* 身份证居住地址
* 1、主体类型为企业时需要填写。其他主体类型无需上传
* 2、请按照身份证住址填写如广东省深圳市南山区xx路xx号xx室
* 3、长度为4-128个字符
* 4、前后不能有空格、制表符、换行符
* 5、不能仅含数字、特殊字符
* 6、仅能填写数字、英文字母、汉字及特殊字符
* 7、仅支持utf-8格式
* 8、 该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
* <a href="https://pay.weixin.qq.com/doc/v3/partner/4013059044">加密</a>
*/
@JSONField(name = "id_card_address")
private String idCardAddress;
/**
* 必填
* 身份证有效期开始时间
* 1、请填写身份证有效期开始时间格式为yyyy-MM-dd
* 2、开始时间不能小于1900-01-01
* 3、开始时间不能大于等于当前日期。
*/
@JSONField(name = "card_period_begin")
private String cardPeriodBegin;
/**
* 必填
* 身份证有效期截止时间
* 1、日期格式应满足合法的YYYY-MM-DD格式或长期
* 2、结束时间需大于开始时间。
*/
@JSONField(name = "card_period_end")
private String cardPeriodEnd;
}

View File

@@ -0,0 +1,100 @@
package com.czg.wechat.dto.req.entry.id;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 其他类型证件信息
* @author yjjie
* @date 2025/12/26 15:42
*/
@Data
@Accessors(chain = true)
public class WechatEntryIdDocInfoReqDto {
/**
* 【必填】
* 证件正面照片
* 1、证件类型不为“身份证”时上传证件正面照片
* 2、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 3、请上传彩色照片or彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 4、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "id_doc_copy")
private String idDocCopy;
/**
* 【选填】
* 证件反面照片
* 1、若证件类型为往来通行证、外国人居留证、港澳居民居住证、台湾居民居住证时上传证件反面照片
* 2、若证件类型为护照无需上传反面照片
* 3、正面拍摄、清晰、四角完整、无反光或遮挡不得翻拍、截图、镜像、PS
* 4、请上传彩色照片or彩色扫描件复印件需加盖公章鲜章可添加“微信支付”相关水印如微信支付认证见【指引文档】
* 5、可上传1张图片请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "id_doc_copy_back")
private String idDocCopyBack;
/**
* 【必填】
* 证件姓名
* 1、请填写经营者/法定代表人的证件姓名;
* 2、长度为2-100个字符
* 3、前后不能有空格、制表符、换行符
* 4、不能仅含数字、特殊字符
* 5、仅能填写数字、英文字母、汉字及特殊字符
* 6、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "id_doc_name")
private String idDocName;
/**
* 【必填】
* 证件号码
* 1、请填写经营者/法定代表人的证件号码:
* 护照限境外人士4-15位 数字|字母|连字符;
* 中国香港居民--来往内地通行证H/h开头+8或10位数字/字母;
* 中国澳门居民--来往内地通行证M/m开头+8或10位数字/字母;
* 中国台湾居民--来往大陆通行证8位数字或10位数字
* 外国人居留证15位 数字|字母;
* 台湾居民居住证/港澳居民居住证17位数字+1位数字|X
* 2、该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "id_doc_number")
private String idDocNumber;
/**
* 【选填】
* 证件居住地址
* 1、主体类型为企业时需要填写。其他主体类型无需上传
* 2、请按照身份证住址填写如广东省深圳市南山区xx路xx号xx室
* 3、长度为4-128个字符
* 4、前后不能有空格、制表符、换行符
* 5、不能仅含数字、特殊字符
* 6、仅能填写数字、英文字母、汉字及特殊字符
* 7、仅支持utf-8格式
* 8、 该字段需要使用微信支付公钥加密推荐请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引也可以使用微信支付平台证书公钥加密参考获取平台证书序列号、平台证书加密敏感信息指引。
*/
@JSONField(name = "id_doc_address")
private String idDocAddress;
/**
* 必填
* 证件有效期开始时间
* 1、日期格式应满足合法的YYYY-MM-DD格式
* 2、开始时间不能小于1900-01-01
* 3、开始时间不能大于等于当前日期。
*/
@JSONField(name = "doc_period_begin")
private String docPeriodBegin;
/**
* 必填
* 证件有效期结束时间
* 1、日期格式应满足合法的YYYY-MM-DD格式或长期
* 2、结束时间需大于开始时间。
*/
@JSONField(name = "doc_period_end")
private String docPeriodEnd;
}

View File

@@ -13,6 +13,7 @@
<description>第三方内容</description>
<modules>
<module>czg-pay</module>
<module>aggregation-pay</module>
</modules>
<artifactId>cash-sdk</artifactId>

View File

@@ -99,7 +99,7 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
if (shopInfo == null) {
throw new CzgException("店铺不存在");
}
if (shopInfo.getExpireTime() != null && (LocalDateTime.now().isAfter(shopInfo.getExpireTime()))) {
if (shopInfo.getExpireTime() != null && (DateUtil.date().toLocalDateTime().isAfter(shopInfo.getExpireTime()))) {
throw new CzgException("店铺已过期,请联系商家");
}
if (SystemConstants.OneZero.ZERO == shopInfo.getOnSale() || shopInfo.getStatus() != SystemConstants.OneZero.ONE) {
@@ -253,7 +253,6 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
@Override
@CacheEvict(key = "#shopInfoEditDTO.id")
public Boolean edit(ShopInfoEditDTO shopInfoEditDTO) {
shopInfoEditDTO.setIsMemberPrice(null);
ShopInfo shopInfo;
if (!StpKit.USER.isAdmin()) {
shopInfo = queryChain().eq(ShopInfo::getId, StpKit.USER.getShopId()).one();
@@ -320,6 +319,8 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
rabbitPublisher.sendOrderDetailStatusMsg(shopInfo.getId().toString(), "shopInfoUpdate");
return true;
}
return false;
}

View File

@@ -22,8 +22,6 @@ import com.czg.market.vo.InviteUserVO;
import com.czg.market.vo.MemberConfigVO;
import com.czg.order.entity.OrderInfo;
import com.czg.service.account.mapper.ShopUserMapper;
import com.czg.service.account.util.FunUtil;
import com.czg.utils.FunUtils;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -63,7 +61,6 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
private MemberLevelConfigService memberLevelConfigService;
@DubboReference
private TbMemberConfigService memberConfigService;
private ShopUser getUserInfo(Long shopUserId) {
ShopUser shopUser = queryChain().eq(ShopUser::getId, shopUserId).one();
if (shopUser == null) {
@@ -243,13 +240,9 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
shopUser.setBirthDay(null);
}
shopUser.setNickName(userInfo.getNickName());
// if (shopUser.getJoinTime() == null) {
// shopUser.setJoinTime(LocalDateTime.now());
// }
boolean b = saveOrUpdate(shopUser);
if (b) {
FunUtils.transactionSafeRun(() -> memberConfigService.joinMemberByCondition(shopId, userId, shopUser));
if (shopUser.getJoinTime() == null) {
shopUser.setJoinTime(LocalDateTime.now());
}
return b;
return saveOrUpdate(shopUser);
}
}

View File

@@ -14,7 +14,6 @@ import com.czg.market.entity.MkPointsUser;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.service.MkPointsUserService;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.service.TbMemberConfigService;
import com.czg.resp.CzgResult;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.ShopConfigMapper;

View File

@@ -26,6 +26,8 @@ import com.czg.market.vo.InviteUserVO;
import com.czg.market.vo.MkDistributionConfigVO;
import com.czg.order.dto.MkDistributionPayDTO;
import com.czg.order.entity.OrderInfo;
import com.czg.market.service.OrderInfoService;
import com.czg.order.service.OrderPaymentService;
import com.czg.sa.StpKit;
import com.czg.service.market.enums.OrderStatusEnums;
import com.czg.service.market.mapper.MkDistributionUserMapper;
@@ -83,6 +85,8 @@ public class MkDistributionUserServiceImpl extends ServiceImpl<MkDistributionUse
private ShopUserService shopUserService;
@DubboReference
private UserInfoService userInfoService;
@DubboReference
private OrderPaymentService orderPaymentService;
@Resource
private OrderInfoService orderInfoService;
@DubboReference
@@ -683,28 +687,25 @@ public class MkDistributionUserServiceImpl extends ServiceImpl<MkDistributionUse
.ne(MkDistributionFlow::getStatus, TableValueConstant.DistributionFlow.Status.REFUND.getCode()));
list.forEach(item -> {
MkDistributionFlow refundFlow = BeanUtil.copyProperties(item, MkDistributionFlow.class);
refundFlow.setStatus(TableValueConstant.DistributionFlow.Status.REFUND.getCode());
refundFlow.setSourceId(item.getId());
refundFlow.setId(null);
refundFlow.setCreateTime(DateUtil.date().toLocalDateTime());
refundFlow.setUpdateTime(DateUtil.date().toLocalDateTime());
if (TableValueConstant.DistributionFlow.Status.PENDING.getCode().equals(item.getStatus())) {
item.setStatus(TableValueConstant.DistributionFlow.Status.REFUND.getCode());
item.setStatus(TableValueConstant.DistributionFlow.Status.SUCCESS.getCode());
// updateIncome(item.getRewardAmount().negate(), BigDecimal.ZERO, BigDecimal.ZERO, item.getDistributionUserId(), item.getUserId(), item.getShopUserId(), item.getShopId(), item.getLevel());
distributionFlowService.updateById(item);
mapper.updateIncome(item.getRewardAmount().negate(), null, null, item.getDistributionUserId(), item.getShopId());
} else {
// 执行扣款
updateIncome(BigDecimal.ZERO, item.getRewardAmount().negate(), BigDecimal.ZERO, item.getDistributionUserId(), item.getUserId(), item.getShopUserId(), item.getShopId(), item.getLevel());
updateShopInfoAmount(item.getShopId(), item.getRewardAmount(), orderId, TableValueConstant.DistributionAmountFlow.Type.REFUND, "分销回退");
}
distributionFlowService.save(refundFlow);
});
}
@Transactional
@Override
public void distributionUserAmount(MkDistributionFlow item, OrderInfo orderInfo) {
ShopUser shopUser = shopUserService.getById(item.getDistributionUserId());
updateShopInfoAmount(orderInfo.getShopId(), item.getRewardAmount().negate(), orderInfo.getId(), TableValueConstant.DistributionAmountFlow.Type.SUB, "分销扣减");
updateIncome(item.getRewardAmount().negate(), item.getRewardAmount(), BigDecimal.ZERO,
item.getDistributionUserId(), shopUser.getUserId(), item.getShopUserId(), item.getShopId(), item.getLevel());
distributionFlowService.updateById(item);
}
@Override
public void distribute(Long sourceId, String orderNo, BigDecimal amount, Long sourceUserId, Long shopId, String type) {
MkDistributionDeliver deliver = new MkDistributionDeliver().setSourceId(sourceId).setOrderNo(orderNo).setShopId(shopId).setType(type).setStatus("success");
@@ -729,13 +730,6 @@ public class MkDistributionUserServiceImpl extends ServiceImpl<MkDistributionUse
distributionDeliverService.save(deliver);
}
/**
* 分销金额修改
*
* @param pendingIncome 待入账金额
* @param receivedIncome 已入账
* @param withdrawIncome 已提现
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateIncome(BigDecimal pendingIncome, BigDecimal receivedIncome, BigDecimal withdrawIncome, Long id, Long userId, Long shopUserId, Long shopId, Integer isOne) {

View File

@@ -192,7 +192,7 @@ public class MkPointsUserServiceImpl extends ServiceImpl<MkPointsUserMapper, MkP
.shopId(pointsUser.getShopId())
.shopUserId(pointsUser.getShopUserId())
.floatType(PointsConstant.SUB.getValue())
.floatPoints(-floatPoints)
.floatPoints(floatPoints)
.balancePoints(pointsUser.getPointBalance())
.sourceId(orderId.toString())
.content(reason)

View File

@@ -72,7 +72,7 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
}
@Override
public MkShopRechargeVO detail(Long shopId) throws CzgException{
public MkShopRechargeVO detail(Long shopId) {
shopId = shopInfoService.getMainIdByShopId(shopId);
ShopInfo shopInfo = shopInfoService.getById(shopId);
if (shopInfo.getMainId() != null) {
@@ -175,9 +175,9 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
// 标准充值
if (rechargeDetailId != null) {
MkShopRechargeDetail rechargeDetail = shopRechargeDetailService.getById(rechargeDetailId);
shopUserMoneyEditDTO.setMoney(rechargeDetail.getAmount());
FunUtils.asyncSafeRunVoid(() -> {
MkShopRechargeDetail rechargeDetail = shopRechargeDetailService.getById(rechargeDetailId);
shopUserMoneyEditDTO.setMoney(rechargeDetail.getAmount());
// 赠送金额
ShopUserMoneyEditDTO shopUserMoneyEditRewardDTO = new ShopUserMoneyEditDTO()
.setId(shopUserId)

View File

@@ -361,7 +361,6 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
memberExpFlowService.save(expFlow);
upShopUser.setExperience(shopUser.getExperience() + exp);
shopUser.setExperience(upShopUser.getExperience());
// 修改会员等级
MemberLevelConfig nextConfig = levelConfigService.getOne(new QueryWrapper().eq(MemberLevelConfig::getShopId, shopUser.getMainShopId())
.gt(MemberLevelConfig::getExperienceValue, levelVO.getExperienceValue()).orderBy(MemberLevelConfig::getExperienceValue, true).limit(1));

View File

@@ -45,33 +45,36 @@
order by a.create_time desc
</select>
<select id="totalAmount" resultType="java.math.BigDecimal">
select sum(a.reward_amount)
from mk_distribution_flow as a
left join tb_shop_user as b on a.shop_user_id = b.id
select sum(a.amount) from mk_distribution_flow as a
left join mk_distribution_user as d on d.id=a.distribution_user_id
left join tb_shop_user as b on a.shop_user_id=b.id
left join tb_shop_user as c on c.id=a.shop_user_id
where a.shop_id=#{shopId}
<if test="id != null">
and a.shop_user_id=#{id}
</if>
<if test="userId != null">
and a.user_id=#{userId}
</if>
<if test="status != null and status != ''">
and a.status=#{status}
</if>
<if test="type != null and type != ''">
and a.type=#{type}
</if>
<if test="startTime != null">
and a.create_time>=#{startTime}
</if>
<if test="endTime != null">
and a.create_time&lt;=#{endTime}
</if>
<if test="status != null and status != ''">
and a.status=#{status}
</if>
<if test="key != null and key != ''">
and (
b.nick_name like concat('%',#{key},'%')
or b.id like concat('%',#{key},'%')
or c.id like concat('%',#{key},'%')
or c.nick_name like concat('%',#{key},'%')
)
</if>
<if test="id != null">
and d.id=#{id}
</if>
<if test="type != null and type != ''">
and a.type=#{type}
</if>
<if test="userId != null">
and d.user_id=#{userId}
</if>
</select>
</mapper>

View File

@@ -5,24 +5,16 @@
<mapper namespace="com.czg.service.market.mapper.MkDistributionUserMapper">
<update id="updateIncome">
update mk_distribution_user
<set>
set
<if test="pendingIncome != null">
total_income = total_income + #{pendingIncome},
</if>
<if test="receivedIncome != null">
total_income = total_income + #{receivedIncome},
</if>
<if test="pendingIncome != null">
pending_income = pending_income + #{pendingIncome},
</if>
<if test="receivedIncome != null">
received_income = received_income + #{receivedIncome},
</if>
<if test="withdrawIncome != null">
withdrawn_income = withdrawn_income + #{withdrawIncome}
</if>
</set>
pending_income = pending_income + #{pendingIncome},
received_income = received_income + #{receivedIncome},
withdrawn_income = withdrawn_income + #{withdrawIncome}
where id = #{id} and shop_id = #{shopId}
</update>

View File

@@ -36,7 +36,7 @@ public class DistributionPayServiceImpl implements DistributionPayService {
private final BigDecimal MONEY_RATE = new BigDecimal("100");
@Resource
private OrderPaymentService paymentService;
private OrderPaymentService orderPaymentService;
@Resource
private MkDistributionConfigService configService;
@Resource
@@ -74,7 +74,7 @@ public class DistributionPayServiceImpl implements DistributionPayService {
.setPayType(PayTypeConstants.PayType.PAY)
.setOrderNo(payParam.getPlatformType() + IdUtil.getSnowflakeNextId())
.setAmount(isRecharge ? payParam.getAmount() : detail.getPayAmount());
paymentService.save(orderPayment);
orderPaymentService.save(orderPayment);
InitInfo initInfo = new InitInfo().setConfig(detail);
if (isRecharge) {

View File

@@ -1060,8 +1060,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
distributionUserService.costUpgradeLevelBefore(orderInfo.getUserId(), orderInfo.getShopId());
// 分销奖励
distributionUserService.distribute(orderInfo.getId(), orderInfo.getOrderNo(), payment.getAmount(), orderInfo.getUserId(), orderInfo.getShopId(), "order");
}
else if (PayTypeConstants.SourceType.MEMBER_IN.equals(payment.getSourceType()) || PayTypeConstants.SourceType.FREE.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.MEMBER_IN.equals(payment.getSourceType()) || PayTypeConstants.SourceType.FREE.equals(payment.getSourceType())) {
boolean isFree = PayTypeConstants.SourceType.FREE.equals(payment.getSourceType());
ShopUser shopUser = shopUserService.getById(payment.getSourceId());
OrderInfo orderInfo = null;
@@ -1113,22 +1112,17 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
payment.getId(), payment.getSourceType(), bizEnum, orderInfo == null);
}
}
}
else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
//购买会员
ShopUser shopUser = shopUserService.getById(payment.getSourceId());
memberConfigService.joinMember(payment.getShopId(), shopUser.getUserId(), payment.getRelatedId());
}
else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
distributionUserService.open(payment.getSourceId(), payment.getAmount(), payment.getShopId(), payment.getId());
}
else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
goodPayService.payCallBack(payment.getSourceId(), payment.getId());
}
else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
gbOrderService.payCallBack(payment.getSourceId(), payment.getId());
}
else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
ppPackageOrderService.paySuccess(payment.getSourceId(), payment.getId());
}
}

View File

@@ -22,10 +22,10 @@ public class OrderPaymentServiceImpl extends ServiceImpl<OrderPaymentMapper, Ord
@Override
public BigDecimal countMemberInAmount(Long shopId, Long shopUserId) {
return getOneAs(QueryWrapper.create().select("IFNULL(sum(amount), 0) as total_amount")
.eq(OrderPayment::getShopId, shopId)
.eq(OrderPayment::getShopId, 143)
.eq(OrderPayment::getSourceType, PayTypeConstants.SourceType.MEMBER_IN)
.eq(OrderPayment::getPayType, PayTypeConstants.PayType.PAY)
.eq(OrderPayment::getSourceId, shopUserId)
.eq(OrderPayment::getSourceId, 127452)
.eq(OrderPayment::getPayStatus, PayTypeConstants.PayStatus.SUCCESS), BigDecimal.class);
}
}

View File

@@ -688,7 +688,10 @@ public class PayServiceImpl implements PayService {
if (orderInfo.getStatus().equals(OrderStatusEnums.CANCELLED.getCode())) {
throw new CzgException("订单已过期不可退单");
}
boolean isFirstRefund = orderInfo.getRefundAmount().compareTo(BigDecimal.ZERO) == 0;
boolean isFirstRefund = true;
if (orderInfo.getRefundAmount().compareTo(BigDecimal.ZERO) != 0) {
isFirstRefund = false;
}
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
Map<String, BigDecimal> returnProMap = new HashMap<>();
boolean isPay = true;
@@ -818,8 +821,8 @@ public class PayServiceImpl implements PayService {
if (!returnProMap.isEmpty()) {
rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderInfo.getId(), "returnProMap", returnProMap)));
}
FunUtils.asyncSafeRunVoid(() -> refundOrderAfter(orderInfo.getId(), orderInfo.getShopId(), orderInfo.getUserId(), orderInfo.getOrderNo(),
orderInfo.getPointsNum(), isFirstRefund, orderInfo.getStatus().equals(OrderStatusEnums.REFUND.getCode())));
refundOrderAfter(orderInfo.getId(), orderInfo.getShopId(), orderInfo.getUserId(), orderInfo.getOrderNo(),
orderInfo.getPointsNum(), isFirstRefund, orderInfo.getStatus().equals(OrderStatusEnums.REFUND.getCode()));
return CzgResult.success();
}
@@ -864,11 +867,12 @@ public class PayServiceImpl implements PayService {
}
throw new CzgException(refund.getMsg());
} else {
OrderPayment uOrderPayment = new OrderPayment();
uOrderPayment.setPayTime(LocalDateTime.now());
uOrderPayment.setTradeNumber(refund.getData().getRefundOrderId());
uOrderPayment.setRespJson(JSONObject.toJSONString(refund.getData()));
paymentService.update(uOrderPayment, QueryWrapper.create().eq(OrderPayment::getId, refundId));
paymentService.updateChain()
.eq(OrderPayment::getId, refundId)
.set(OrderPayment::getPayTime, refund.getData().getRefundTime())
.set(OrderPayment::getTradeNumber, refund.getData().getRefundOrderId())
.set(OrderPayment::getRespJson, JSONObject.toJSONString(refund.getData()))
.update();
}
}