82 Commits

Author SHA1 Message Date
c446d576be 支付调整 2026-01-14 17:06:11 +08:00
ab8877c9cf Merge remote-tracking branch 'origin/test' into test
# Conflicts:
#	cash-api/order-server/src/main/java/com/czg/controller/NotifyController.java
#	cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java
2026-01-14 17:06:04 +08:00
4eaedcce41 支付调整 2026-01-14 17:04:48 +08:00
gong
a5982abe20 加急菜品 orderDetail 开始订单时间 2026-01-14 15:06:21 +08:00
gong
946fe4de4c 回调处理 2026-01-14 14:41:30 +08:00
gong
e341630e82 微信退款 2026-01-14 13:54:37 +08:00
gong
f12e7f9802 修改进件资料时 判断修改进件状态 2026-01-14 11:32:35 +08:00
gong
e798781ca0 微信查询订单 2026-01-14 11:28:00 +08:00
gong
e8be5dee9d 微信条码支付 2026-01-14 10:35:33 +08:00
gong
4faec74cda 微信提交信息修改 2026-01-13 15:56:17 +08:00
dbe1305811 赠送问题 2026-01-13 15:20:37 +08:00
77de98fd58 打印 菜品 声音 2026-01-13 14:35:28 +08:00
b0aaf15413 打印 菜品 声音 2026-01-13 14:29:57 +08:00
a28b903b73 userID 为空 2026-01-13 14:05:50 +08:00
gong
61f5f1a0bb 修改进件状态 2026-01-13 09:21:39 +08:00
gong
36523143ba 审核中 获取签约地址 状态改为待审核 2026-01-12 17:38:57 +08:00
gong
ad3454143a 审核中 获取签约地址 2026-01-12 17:33:02 +08:00
gong
cd9eb70283 微信响应结果处理 2026-01-12 17:01:48 +08:00
deb3d81e0d 银行支行 空值 2026-01-12 11:10:46 +08:00
692a504da3 银行支行 区域 2026-01-12 10:35:49 +08:00
gong
15a631383b 更新查询银行支行列表使用 微信 2026-01-12 09:42:37 +08:00
33c6a10d19 文件 过大 问题 2026-01-09 18:37:12 +08:00
89a98123e7 文件 过大 问题 2026-01-09 18:34:13 +08:00
a6991905b8 文件 过大 问题 2026-01-09 18:27:06 +08:00
38f1dc9d1f 回填上传id 2026-01-09 18:21:44 +08:00
gong
021a837c1b 微信 Wechatpay-Serial 2026-01-09 18:18:53 +08:00
gong
3a5bd9e994 支付宝 直付通参数配置 2026-01-09 18:03:14 +08:00
gong
dfd2c74c33 微信支付修改 2026-01-09 17:33:32 +08:00
9b74b38799 更新 2026-01-09 17:06:44 +08:00
gong
0513cd5e65 微信请求 header 添加 Wechatpay-Serial 2026-01-09 17:06:11 +08:00
gong
8cbf20e751 EntryThirdRespDto 为 null 的情况 2026-01-09 16:58:26 +08:00
e203d7275a 进件标识 2026-01-09 16:55:40 +08:00
504e9b131c 进件标识 2026-01-09 16:52:03 +08:00
ef8eabb06c mq问题 2026-01-09 16:49:22 +08:00
16a814568d where 标签 2026-01-09 16:15:04 +08:00
e3bf70ab9e MQ 2026-01-09 16:10:04 +08:00
7ac540dfa9 MQ 2026-01-09 15:59:37 +08:00
423423ca0b 关联主键 2026-01-09 15:54:52 +08:00
gong
4e686c9c8e 微信进件 bug 修复 2026-01-09 15:53:24 +08:00
d7233545c7 提出字段
新增 列表接口
2026-01-09 15:46:18 +08:00
cab370d1e1 新增 支付宝授权参数 2026-01-09 11:29:53 +08:00
gong
3a70c1ced3 当面付进件修改1 2026-01-09 10:51:44 +08:00
gong
db3c635197 当面付进件修改1 2026-01-09 10:51:31 +08:00
gong
6180cc6801 Merge branch 'pay' into test 2026-01-08 18:19:40 +08:00
4d6715ac9e Merge branch 'pay' into test 2026-01-08 16:33:36 +08:00
36a6a21987 Merge branch 'pay' into test 2026-01-08 16:21:42 +08:00
ec0e281cfa 接口名称问题 2026-01-08 10:57:07 +08:00
59932b00f4 Merge branch 'pay' into test
# Conflicts:
#	cash-api/order-server/src/main/java/com/czg/mq/PrintMqListener.java
2026-01-08 10:50:18 +08:00
e8b2924d60 计算成本价问题 2026-01-05 14:32:19 +08:00
f3c42856fc 统计 2026-01-05 11:28:28 +08:00
0b02f66fb5 shop_user查询多个的问题 2026-01-05 09:38:17 +08:00
acf04b8534 开关标识 2025-12-31 09:24:09 +08:00
cc8be70559 重新打印问题 失败标识问题 2025-12-30 15:21:58 +08:00
ee635dcc32 日期格式问题 2025-12-30 15:17:52 +08:00
dc7146942b 赋值问题 2025-12-30 15:05:06 +08:00
93b2309fcd 修改标识 2025-12-30 14:25:37 +08:00
0684e0459f 修改标识 2025-12-30 14:11:38 +08:00
a4fc02dcc3 文档地址 2025-12-30 13:55:11 +08:00
d854ff9e30 MQ重试 2025-12-30 13:32:16 +08:00
befd2942a2 打印问题 2025-12-30 11:49:54 +08:00
7384b67c50 打印问题 2025-12-30 10:23:04 +08:00
329d9dfb3d 快捷菜单 2025-12-29 17:59:50 +08:00
0ca2a6c7f8 快捷菜单 2025-12-29 16:30:50 +08:00
58104d2afa 快捷菜单 2025-12-29 16:28:09 +08:00
3d6061342a Merge remote-tracking branch 'origin/test' into test 2025-12-29 15:49:01 +08:00
76f6e7776e 打印机类型 2025-12-29 15:47:02 +08:00
gong
87797e5812 关联商品查询同步商品 2025-12-29 15:32:23 +08:00
057f851dcf 返回数据 尝试 2025-12-29 14:51:26 +08:00
dc3be2f1d8 打印状态字段 2025-12-29 14:40:39 +08:00
232bfe84df 多余打印 2025-12-29 14:29:10 +08:00
ff09e8e92b 打印状态标识 允许重新操作 2025-12-29 14:26:51 +08:00
5d9c01f427 打印状态标识 允许重新操作 2025-12-29 14:23:05 +08:00
5d7aaa2dca 企业Id 信息 2025-12-29 10:08:25 +08:00
5595a8009b 绑定手机号 判断 是否成为 会员 2025-12-26 11:42:18 +08:00
233c226dca 精简sql 2025-12-26 11:34:22 +08:00
76c6e12c72 统计充值金额 2025-12-26 11:19:43 +08:00
5b030ea361 名字问题 2025-12-26 11:06:07 +08:00
266e782fc0 Merge branch 'dev' into prod 2025-12-26 10:50:58 +08:00
aa7483b1b1 临时菜标识
扣除积分 负数
2025-12-26 10:49:36 +08:00
7eeeb8a30f 分销 定时任务 2025-12-26 10:44:43 +08:00
70307e3833 分销问题
会员充值问题
2025-12-26 10:37:32 +08:00
8bde6b15f6 成长值问题 2025-12-26 09:24:28 +08:00
147 changed files with 3855 additions and 1958 deletions

View File

@@ -1,39 +0,0 @@
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

@@ -4,14 +4,18 @@ import com.czg.account.dto.menu.MenuAddDTO;
import com.czg.account.dto.menu.MenuDelDTO;
import com.czg.account.dto.menu.MenuEditDTO;
import com.czg.account.entity.CashMenu;
import com.czg.account.entity.QuickMenu;
import com.czg.account.entity.SysMenu;
import com.czg.account.service.QuickMenuService;
import com.czg.account.service.SysMenuService;
import com.czg.account.vo.MenuVO;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.annotation.SaAdminCheckRole;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -19,6 +23,7 @@ import java.util.List;
/**
* 菜单管理
*
* @author zs
*/
@RestController
@@ -27,9 +32,12 @@ public class MenuController {
@Resource
private SysMenuService menuService;
@Resource
private QuickMenuService quickMenuService;
/**
* 获取当前用户菜单列表
*
* @return 菜单结构
*/
@GetMapping
@@ -40,6 +48,7 @@ public class MenuController {
/**
* 收银机菜单
*
* @return 所有菜单
*/
@GetMapping("/list/cash")
@@ -49,6 +58,7 @@ public class MenuController {
/**
* 获取所有菜单
*
* @return 菜单结构
*/
@SaAdminCheckPermission(parentName = "菜单管理", value = "menu:list", name = "菜单列表")
@@ -62,6 +72,7 @@ public class MenuController {
/**
* 菜单详情
*
* @return 菜单结构
*/
@SaAdminCheckRole("管理员")
@@ -73,6 +84,7 @@ public class MenuController {
/**
* 菜单添加
*
* @return 是否成功
*/
@SaAdminCheckRole("管理员")
@@ -84,6 +96,7 @@ public class MenuController {
/**
* 菜单修改
*
* @return 是否成功
*/
@SaAdminCheckRole("管理员")
@@ -95,12 +108,15 @@ public class MenuController {
/**
* 菜单删除
*
* @return 是否成功
*/
@SaAdminCheckRole("管理员")
@SaAdminCheckPermission(parentName = "菜单管理", value = "menu:del", name = "菜单删除")
@DeleteMapping()
@Transactional
public CzgResult<Boolean> edit(@RequestBody @Validated MenuDelDTO menuDelDTO) {
quickMenuService.remove(QueryWrapper.create().eq(QuickMenu::getMenuId, menuDelDTO.getId()));
return CzgResult.success(menuService.removeById(menuDelDTO.getId()));
}

View File

@@ -0,0 +1,70 @@
package com.czg.controller.admin;
import cn.hutool.core.collection.CollUtil;
import com.czg.account.entity.QuickMenu;
import com.czg.account.service.QuickMenuService;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;
/**
* 悬浮窗/快捷菜单
*
* @author ww
* @description
*/
@RestController
@RequestMapping("/admin/quick")
@Slf4j
public class QuickMenuController {
@Resource
private QuickMenuService quickMenuService;
@SaAdminCheckPermission(parentName = "悬浮窗", value = "quick:list", name = "悬浮窗-列表")
@GetMapping
public CzgResult<List<QuickMenu>> getQuickList(@RequestParam(required = false) Integer status,
@RequestParam(required = false, defaultValue = "0") Integer isEdit) {
List<QuickMenu> list = quickMenuService.list(QueryWrapper.create()
.eq(QuickMenu::getShopId, StpKit.USER.getShopId())
.eq(QuickMenu::getStatus, status)
.orderBy(QuickMenu::getSort, true));
if (isEdit.equals(0)) {
if (CollUtil.isEmpty(list)) {
list = quickMenuService.list(QueryWrapper.create()
.eq(QuickMenu::getShopId, 1)
.eq(QuickMenu::getStatus, status)
.orderBy(QuickMenu::getSort, true));
}
}
return CzgResult.success(list);
}
@SaAdminCheckPermission(parentName = "悬浮窗", value = "quick:list", name = "悬浮窗-新增")
@PostMapping
public CzgResult<Boolean> saveQuick(@RequestBody @Validated QuickMenu quickMenu) {
quickMenu.setShopId(StpKit.USER.getShopId());
return CzgResult.success(quickMenuService.save(quickMenu));
}
@SaAdminCheckPermission(parentName = "悬浮窗", value = "quick:list", name = "悬浮窗-修改")
@PutMapping
public CzgResult<Boolean> updateQuick(@RequestBody @Validated QuickMenu quickMenu) {
return CzgResult.success(quickMenuService.update(quickMenu, QueryWrapper.create()
.eq(QuickMenu::getId, quickMenu.getId()).eq(QuickMenu::getShopId, StpKit.USER.getShopId())));
}
@SaAdminCheckPermission(parentName = "悬浮窗", value = "quick:list", name = "悬浮窗-删除")
@DeleteMapping
public CzgResult<Boolean> deleteQuick(@RequestBody Set<Long> ids) {
return CzgResult.success(quickMenuService.remove(QueryWrapper.create().in(QuickMenu::getId, ids).eq(QuickMenu::getShopId, StpKit.USER.getShopId())));
}
}

View File

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

View File

@@ -1,18 +1,17 @@
package com.czg.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.ShopInfo;
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;
import com.czg.market.service.OrderInfoService;
import com.czg.order.entity.OrderInfo;
import com.czg.service.market.enums.OrderStatusEnums;
import com.czg.utils.FunUtils;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -40,8 +39,6 @@ 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());
@@ -51,44 +48,55 @@ public class DistributionTask {
*/
// @Scheduled(cron = "0 0 0 * * ?")
// @Scheduled(fixedRate = 30000)
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;
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;
}
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);
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;
}
});
});
}
}
}
}

View File

@@ -4,8 +4,12 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.CzgPayUtils;
import com.czg.PayCst;
import com.czg.constants.PayTypeConstants;
import com.czg.dto.req.WechatNotifyReqDto;
import com.czg.dto.req.WechatPayNotifyDataDto;
import com.czg.entity.CzgBaseRespParams;
import com.czg.exception.CzgException;
import com.czg.market.entity.MkShopConsumeDiscountRecord;
import com.czg.market.service.MkDistributionUserService;
import com.czg.market.service.MkShopConsumeDiscountRecordService;
@@ -15,15 +19,13 @@ import com.czg.order.entity.OrderPayment;
import com.czg.order.service.OrderInfoCustomService;
import com.czg.order.service.OrderPaymentService;
import com.czg.service.market.service.impl.AppWxServiceImpl;
import com.czg.third.wechat.WechatReqUtils;
import com.czg.utils.AssertUtil;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
@@ -50,6 +52,8 @@ public class NotifyController {
@Resource
private MkShopConsumeDiscountRecordService consumeDiscountRecordService;
//新客立减清除数据 测试用
@RequestMapping("clear")
public String clear(@RequestParam Integer shopId) {
consumeDiscountRecordService.remove(new QueryWrapper().eq(MkShopConsumeDiscountRecord::getShopId, shopId));
@@ -57,6 +61,48 @@ public class NotifyController {
return "success";
}
/**
* 原生支付回调
*/
@RequestMapping("/native/pay/{platform}")
public String pay(@PathVariable String platform, @RequestBody JSONObject json) {
if (PayCst.Platform.WECHAT.equalsIgnoreCase(platform)) {
// 微信
WechatNotifyReqDto reqDto = JSONObject.parseObject(json.toJSONString(), WechatNotifyReqDto.class);
log.info("【微信支付回调】收到微信支付回调 data: {}", JSONObject.toJSONString(reqDto));
String decrypted = WechatReqUtils.decryptRespParam(null, reqDto);
log.info("【微信支付回调】解密数据 {}", decrypted);
WechatPayNotifyDataDto dataDto = JSONObject.parseObject(decrypted, WechatPayNotifyDataDto.class);
return "success";
} else if (PayCst.Platform.ALIPAY.equalsIgnoreCase(platform)) {
// 支付宝
return "success";
}
throw new CzgException("不支持的支付平台");
}
/**
* 原生退款回调
*/
@RequestMapping("/native/refund/{platform}")
public String refund(@PathVariable String platform, @RequestBody JSONObject json) {
if (PayCst.Platform.WECHAT.equalsIgnoreCase(platform)) {
// 微信
WechatNotifyReqDto reqDto = JSONObject.parseObject(json.toJSONString(), WechatNotifyReqDto.class);
log.info("【微信退款回调】收到微信退款回调 data: {}", JSONObject.toJSONString(reqDto));
String decrypted = WechatReqUtils.decryptRespParam(null, reqDto);
log.info("【微信退款回调】解密数据 {}", decrypted);
return "success";
} else if (PayCst.Platform.ALIPAY.equalsIgnoreCase(platform)) {
// 支付宝
return "success";
}
throw new CzgException("不支持的支付平台");
}
@RequestMapping("/payCallBack")
public String notifyCallBack(@RequestBody CzgBaseRespParams respParams) {

View File

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

View File

@@ -3,19 +3,21 @@ package com.czg.controller.admin;
import com.alibaba.fastjson2.JSONObject;
import com.czg.EntryManager;
import com.czg.annotation.Debounce;
import com.czg.config.RabbitPublisher;
import com.czg.dto.req.AggregateMerchantDto;
import com.czg.dto.resp.BankBranchDto;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.czg.dto.resp.WechatBankBranchRespDto;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.czg.service.order.dto.MerchantQueryDTO;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.czg.task.EntryManagerTask;
import com.czg.utils.AssertUtil;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 进件管理
*
@@ -31,6 +33,9 @@ public class EntryManagerController {
@Resource
private EntryManagerTask entryManagerTask;
@Resource
private RabbitPublisher rabbitPublisher;
/**
* ocr识别填充
* 阿里 ocr识别图片
@@ -53,13 +58,28 @@ public class EntryManagerController {
/**
* 查询银行支行列表
*
* @param province 省份 陕西省 从 /system/admin/common/region获取
* @param city 城市 西安市 从 /system/admin/common/region获取
* @param instId 顶级机构ID CMB 从 /system/admin/common/bankInfo 获取
* @param bankAliceCode 银行别名code bankAliasCode /system/admin/common/bankInfo 获取
* @param cityCode 市编码 wxProvinceCode 从 /system/admin/common/region 获取
*/
@GetMapping("bankBranchList")
public CzgResult<List<BankBranchDto>> queryBankBranchList(String province, String city, String instId) {
return CzgResult.success(EntryManager.queryBankBranchList(province, city, instId));
public CzgResult<WechatBankBranchRespDto> queryBankBranchList(String bankAliceCode, String cityCode) {
AssertUtil.isBlank(bankAliceCode, "请选择银行别名");
AssertUtil.isBlank(cityCode, "请选择城市");
return CzgResult.success(EntryManager.queryBankBranchList(bankAliceCode, cityCode));
}
@GetMapping("test")
public CzgResult<Void> test(String shopId, String licenceNo) {
rabbitPublisher.sendEntryManagerMsg(shopId + ":" + licenceNo);
return CzgResult.success();
}
/**
* 获取进件列表
*/
@GetMapping("list")
public CzgResult<Page<ShopDirectMerchant>> getEntryList(MerchantQueryDTO queryParam) {
return CzgResult.success(shopDirectMerchantService.getEntryList(queryParam));
}
@@ -67,8 +87,8 @@ public class EntryManagerController {
* 获取进件信息
*/
@GetMapping
public CzgResult<AggregateMerchantVO> getEntry(Long shopId) {
return CzgResult.success(shopDirectMerchantService.getEntry(shopId));
public CzgResult<AggregateMerchantVO> getEntry(Long shopId, String licenceNo) {
return CzgResult.success(shopDirectMerchantService.getEntry(shopId, licenceNo));
}
/**
@@ -78,8 +98,8 @@ public class EntryManagerController {
*/
@GetMapping("queryEntry")
@Debounce(value = "#shopId", interval = 1000 * 60 * 3)
public CzgResult<Boolean> queryEntry(Long shopId) {
entryManagerTask.entryManager(shopId);
public CzgResult<Boolean> queryEntry(Long shopId, String licenceNo) {
entryManagerTask.entryManager(shopId, licenceNo);
return CzgResult.success();
}

View File

@@ -1,18 +1,18 @@
package com.czg.controller.admin;
import com.czg.account.dto.merchant.ShopMerchantEditDTO;
import com.czg.account.entity.ShopMerchant;
import com.czg.account.service.ShopMerchantService;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.annotation.SaAdminCheckRole;
import com.czg.order.dto.ShopMerchantDTO;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.order.service.ShopMerchantService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 商户信息管理
*
* @author Administrator
*/
@RestController
@@ -24,25 +24,36 @@ public class ShopMerchantController {
/**
* 商户支付信息获取
* 权限标识: shopMerchant:detail
*
* @param shopId 店铺id
* @return 支付信息
*/
@SaAdminCheckRole("管理员")
@SaAdminCheckPermission(parentName = "支付参数信息", value = "shopMerchant:detail", name = "商户支付信息获取")
@GetMapping
public CzgResult<ShopMerchant> detail(@RequestParam Integer shopId) {
public CzgResult<ShopMerchantDTO> detail(@RequestParam Long shopId) {
return CzgResult.success(shopMerchantService.detail(shopId));
}
/**
* 商户支付信息修改
* 权限标识: shopMerchant:edit
*
* @return 是否成功
*/
@SaAdminCheckRole("管理员")
@SaAdminCheckPermission(parentName = "支付参数信息", value = "shopMerchant:edit", name = "商户支付信息修改")
@PutMapping
public CzgResult<Boolean> edit(@RequestBody @Validated ShopMerchantEditDTO shopMerchantEditDTO) {
return CzgResult.success(shopMerchantService.edit(shopMerchantEditDTO));
public CzgResult<Boolean> edit(@RequestBody ShopMerchantDTO shopMerchant) {
shopMerchant.setShopId(StpKit.USER.getShopId());
return CzgResult.success(shopMerchantService.editEntry(shopMerchant, true));
}
/**
* 获取当前店铺的主店进件信息
*/
@GetMapping("getMainMerchant")
public CzgResult<ShopDirectMerchant> getMainMerchant() {
return CzgResult.success(shopMerchantService.getMainMerchant(StpKit.USER.getShopId()));
}
}

View File

@@ -4,14 +4,15 @@ import com.czg.annotation.Debounce;
import com.czg.order.dto.MkDistributionPayDTO;
import com.czg.resp.CzgResult;
import com.czg.service.order.service.DistributionPayService;
import com.czg.system.service.SysParamsService;
import com.czg.utils.AssertUtil;
import com.czg.utils.ServletUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@@ -26,16 +27,6 @@ import java.util.Map;
public class DistributionPayController {
@Resource
private DistributionPayService payService;
@DubboReference
private SysParamsService paramsService;
// @PostMapping("/cashPay")
// @Debounce(value = "#payParam.checkOrderPay.orderId")
// public CzgResult<Object> cashPayOrder(@RequestHeader Long shopId, @Validated @RequestBody MkDistributionPayDTO payParam) {
// payParam.setShopId(shopId);
// return payService.cashPayOrder(payParam);
// }
/**
* 小程序支付
@@ -44,7 +35,7 @@ public class DistributionPayController {
*/
@PostMapping("/ltPayOrder")
@Debounce(value = "#payParam.userId")
public CzgResult<Map<String, Object>> ltPayOrder( HttpServletRequest request, @Validated @RequestBody MkDistributionPayDTO payParam) {
public CzgResult<Map<String, Object>> ltPayOrder(HttpServletRequest request, @Validated @RequestBody MkDistributionPayDTO payParam) {
return payService.ltPayOrder(ServletUtil.getClientIP(request), payParam);
}
@@ -55,30 +46,8 @@ public class DistributionPayController {
*/
@PostMapping("/mchRecharge")
@Debounce(value = "#payParam.userId")
public CzgResult<Map<String, String>> mchRecharge(HttpServletRequest request, @Validated @RequestBody MkDistributionPayDTO payParam) {
public CzgResult<Map<String, String>> mchRecharge(@Validated @RequestBody MkDistributionPayDTO payParam) {
AssertUtil.isBlank(payParam.getCode(), "微信code不为空");
return CzgResult.success(payService.mchRecharge(ServletUtil.getClientIP(request), payParam));
return CzgResult.success(payService.mchRecharge(payParam));
}
//
// /**
// * 正扫
// */
// @PostMapping("/scanPay")
// @Debounce(value = "#payParam.checkOrderPay.orderId")
// public CzgResult<Map<String, Object>> scanPayOrder(@RequestHeader Long shopId, HttpServletRequest request, @Validated @RequestBody MkDistributionPayDTO payParam) {
// payParam.setShopId(shopId);
// return payService.scanPayOrder(ServletUtil.getClientIP(request), payParam);
// }
//
// /**
// * 反扫
// * authCode 必填 扫描码
// */
// @PostMapping("/microPay")
// @Debounce(value = "#payParam.checkOrderPay.orderId")
// public CzgResult<Map<String, Object>> microPayOrder(@RequestHeader Long shopId, @Validated @RequestBody MkDistributionPayDTO payParam) {
// payParam.setShopId(shopId);
// return payService.microPayOrder(payParam);
// }
}

View File

@@ -1,6 +1,7 @@
package com.czg.mq;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.EntryManager;
import com.czg.PayCst;
import com.czg.config.RabbitConstants;
@@ -10,6 +11,7 @@ import com.czg.order.entity.ShopDirectMerchant;
import com.czg.service.RedisService;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.mybatisflex.core.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -48,20 +50,33 @@ public class EntryManagerMqListener {
)
@RabbitHandler
public void handle(Message message, Channel channel, String msg) throws IOException {
String messageId = message.getMessageProperties().getMessageId();
if (hasMessageId(messageId)) {
log.info("进件1MQ对接开始 店铺标识:{}", msg);
long deliveryTag = message.getMessageProperties().getDeliveryTag();
if (StrUtil.isBlank(msg)) {
channel.basicNack(deliveryTag, false, false);
return;
}
String[] split = msg.split(":");
if (split.length != 2) {
log.error("进件MQ对接参数异常 店铺标识:{}", msg);
channel.basicNack(deliveryTag, false, false);
return;
}
Long shopId = Long.valueOf(split[0]);
if (shopId == null) {
channel.basicNack(deliveryTag, false, false);
return;
}
if (hasMessageId(msg)) {
return;
}
try {
Long shopId = Long.valueOf(msg);
// 将唯一标识添加到日志上下文
ThreadContext.put("traceId", messageId);
ThreadContext.put("traceId", String.valueOf(shopId));
log.info("进件2MQ对接开始shopId:{}", msg);
// 安全转换shopId
if (shopId == null) {
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
return;
}
AggregateMerchantVO entry = shopDirectMerchantService.getEntry(Long.valueOf(msg));
AggregateMerchantVO entry = shopDirectMerchantService.getEntry(shopId, split[1]);
log.info("进件3MQ对接开始shopId:{}", msg);
if (entry != null) {
EntryManager.uploadParamImage(entry);
List<String> platform = new ArrayList<>();
@@ -73,31 +88,34 @@ public class EntryManagerMqListener {
}
EntryRespDto resp = EntryManager.entryMerchant(entry, platform.toArray(new String[0]));
ShopDirectMerchant merchant = new ShopDirectMerchant();
merchant.setShopId(entry.getShopId());
merchant.setMerchantBaseInfo(JSONObject.toJSONString(entry.getMerchantBaseInfo()));
merchant.setLegalPersonInfo(JSONObject.toJSONString(entry.getLegalPersonInfo()));
merchant.setBusinessLicenceInfo(JSONObject.toJSONString(entry.getBusinessLicenceInfo()));
merchant.setStoreInfo(JSONObject.toJSONString(entry.getStoreInfo()));
merchant.setSettlementInfo(JSONObject.toJSONString(entry.getSettlementInfo()));
merchant.setWechatApplyId(resp.getWechatApplyId());
merchant.setWechatStatus(resp.getWechatStatus());
merchant.setWechatErrorMsg(resp.getWechatErrorMsg());
merchant.setAlipayOrderId(resp.getAlipayOrderId());
merchant.setAlipayStatus(resp.getAlipayStatus());
merchant.setAlipayAuthInfo(resp.getAlipayAuthInfo());
merchant.setAlipayErrorMsg(resp.getAlipayErrorMsg());
shopDirectMerchantService.updateById(merchant);
shopDirectMerchantService.update(merchant, new QueryWrapper().eq(ShopDirectMerchant::getShopId, shopId).eq(ShopDirectMerchant::getLicenceNo, split[1]));
}
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("进件MQ对接业务异常shopId:{}", msg, e);
ShopDirectMerchant merchant = new ShopDirectMerchant();
merchant.setShopId(Long.valueOf(msg));
merchant.setWechatStatus(PayCst.EntryStatus.REJECTED);
merchant.setAlipayStatus(PayCst.EntryStatus.REJECTED);
merchant.setErrorMsg("系统错误,请联系管理员后重试。");
shopDirectMerchantService.updateById(merchant);
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
shopDirectMerchantService.update(merchant, new QueryWrapper().eq(ShopDirectMerchant::getShopId, shopId).eq(ShopDirectMerchant::getLicenceNo, split[1]));
channel.basicNack(deliveryTag, false, false);
} finally {
delMessageId(messageId);
// 清除日志上下文信息
delMessageId(msg);
// 清除日志上下文信息
ThreadContext.remove("messageId");
}
}

View File

@@ -9,7 +9,7 @@ import com.czg.order.entity.MqLog;
import com.czg.order.service.MqLogService;
import com.czg.order.service.OrderInfoCustomService;
import com.czg.order.service.OrderInfoRpcService;
import com.czg.service.order.utils.FunUtil;
import com.czg.service.RedisService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
@@ -31,7 +31,7 @@ public class OrderMqListener {
@Resource
private OrderInfoCustomService orderInfoCustomService;
@Resource
private FunUtil funUtil;
private RedisService redisService;
/**
* 订单上菜
@@ -44,7 +44,7 @@ public class OrderMqListener {
info = info.replace("UP_ORDER_DETAIL:", "");
log.info("接收到修改菜品状态mq, info: {}", info);
String finalInfo = info;
funUtil.debounce("UP_ORDER_DETAIL:" + info, 5, () -> {
redisService.debounce("UP_ORDER_DETAIL:" + info, 5, () -> {
orderInfoCustomService.updateOrderDetailStatus(Long.valueOf(finalInfo));
});

View File

@@ -4,14 +4,12 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.EntryManager;
import com.czg.PayCst;
import com.czg.account.entity.ShopInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.constant.PayChannelCst;
import com.czg.dto.resp.QueryStatusResp;
import com.czg.order.dto.ShopMerchantDTO;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.order.service.ShopOrderStatisticService;
import com.czg.order.service.ShopProdStatisticService;
import com.czg.order.service.ShopTableOrderStatisticService;
import com.czg.service.RedisService;
import com.czg.order.service.ShopMerchantService;
import com.czg.pay.NativeMerchantDTO;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
@@ -20,8 +18,6 @@ import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
@@ -35,23 +31,24 @@ public class EntryManagerTask {
@Resource
private ShopDirectMerchantService shopDirectMerchantService;
@DubboReference
private ShopInfoService shopInfoService;
private ShopMerchantService shopMerchantService;
//每10分钟查一次
@Scheduled(cron = "0 0/10 * * * ? ")
public void run() {
log.info("进件查询,定时任务执行");
long start = System.currentTimeMillis();
entryManager(null);
entryManager(null, null);
log.info("进件查询,定时任务执行完毕,耗时:{}ms", start - System.currentTimeMillis());
}
/**
* 查询状态为待处理、待签约、待审核的进件
*/
public void entryManager(Long shopId) {
public void entryManager(Long shopId, String licenceNo) {
List<ShopDirectMerchant> list = shopDirectMerchantService.list(QueryWrapper.create()
.eq(ShopDirectMerchant::getShopId, shopId)
.eq(ShopDirectMerchant::getLicenceNo, licenceNo)
.in(ShopDirectMerchant::getWechatStatus, PayCst.EntryStatus.NEED_QUERY_LIST)
.or(ShopDirectMerchant::getAlipayStatus).in(PayCst.EntryStatus.NEED_QUERY_LIST));
if (CollUtil.isEmpty(list)) {
@@ -64,7 +61,8 @@ public class EntryManagerTask {
QueryStatusResp wechatStatus = EntryManager.queryWechatEntryStatus(shopDirectMerchant.getWechatApplyId());
shopDirectMerchant.setWechatStatus(wechatStatus.getStatus());
shopDirectMerchant.setWechatErrorMsg(wechatStatus.getFailReason());
shopDirectMerchant.setWechatSignUrl(wechatStatus.getSignUrl());
shopDirectMerchant.setWechatSignUrl("");
shopDirectMerchant.setWechatMerchantId(wechatStatus.getThirdMerchantId());
if (PayCst.EntryStatus.FINISH.equals(wechatStatus.getStatus())) {
wechatMerchantId = wechatStatus.getThirdMerchantId();
}
@@ -73,14 +71,24 @@ public class EntryManagerTask {
QueryStatusResp alipayStatus = EntryManager.queryAlipayEntryStatus(shopDirectMerchant.getAlipayOrderId());
shopDirectMerchant.setAlipayStatus(alipayStatus.getStatus());
shopDirectMerchant.setAlipayErrorMsg(alipayStatus.getFailReason());
shopDirectMerchant.setAlipaySignUrl(alipayStatus.getSignUrl());
shopDirectMerchant.setAlipaySignUrl("");
shopDirectMerchant.setAlipayMerchantId(alipayStatus.getThirdMerchantId());
if (PayCst.EntryStatus.FINISH.equals(alipayStatus.getStatus())) {
alipayMerchantId = alipayStatus.getThirdMerchantId();
}
}
shopDirectMerchantService.updateById(shopDirectMerchant);
if (StrUtil.isNotBlank(wechatMerchantId) || StrUtil.isNotBlank(alipayMerchantId)) {
shopInfoService.editEntry(shopDirectMerchant.getShopId(), wechatMerchantId, alipayMerchantId);
ShopMerchantDTO shopMerchantDTO = new ShopMerchantDTO();
shopMerchantDTO.setShopId(shopId);
shopMerchantDTO.setChannel(PayChannelCst.NATIVE);
shopMerchantDTO.setRelatedLicenceNo(licenceNo);
NativeMerchantDTO nativeMerchantDTO = new NativeMerchantDTO();
nativeMerchantDTO.setWechatMerchantId(wechatMerchantId);
nativeMerchantDTO.setAlipayMerchantId(alipayMerchantId);
shopMerchantDTO.setNativeMerchantDTO(nativeMerchantDTO);
shopMerchantDTO.setNativeMerchantDTO(nativeMerchantDTO);
shopMerchantService.editEntry(shopMerchantDTO, false);
}
}
}

View File

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

View File

@@ -25,7 +25,23 @@ spring:
port: 5672
username: chaozg
password: chaozg123
# 关键优化解决MissedHeartbeatException 心跳超时问题
connection-timeout: 10000 # 连接超时时间10秒避免连接建立过慢
requested-heartbeat: 30 # 心跳间隔调整为30秒原60秒过长降低超时概率过短易误触发
# 自动重连配置Spring AMQP 自带,关键兜底)
publisher-returns: true
template:
retry:
enabled: true # 开启消息发送重试
max-attempts: 3 # 最大重试次数
initial-interval: 3000 # 首次重试间隔2秒
multiplier: 1.5 # 重试间隔倍增因子
listener:
simple:
retry:
enabled: true # 开启消费者重试
max-attempts: 3 # 消费者最大重试次数
acknowledge-mode: auto # 确认模式可根据业务改为manual
dubbo:
application:
name: order-server

View File

@@ -3,7 +3,6 @@ package com.czg.controller.admin;
import com.czg.BaseQueryParam;
import com.czg.resp.CzgResult;
import com.czg.system.entity.SysBankInfo;
import com.czg.system.entity.SysCategoryInfo;
import com.czg.system.entity.SysRegion;
import com.czg.system.service.SysBankInfoService;
import com.czg.system.service.SysCategoryInfoService;
@@ -17,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 通用

View File

@@ -54,7 +54,7 @@ public class FilteredNacosRegistry extends NacosRegistry {
public void register(URL url) {
// 1. 获取原始注册的方法列表
String originalMethods = url.getParameter("methods");
log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), originalMethods);
// log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), originalMethods);
if (originalMethods != null && !originalMethods.isEmpty()) {
// 2. 过滤黑名单中的方法名
List<String> filteredMethods = Arrays.stream(originalMethods.split(","))
@@ -67,12 +67,12 @@ public class FilteredNacosRegistry extends NacosRegistry {
// 3. 处理过滤后的结果
if (filteredMethods.isEmpty()) {
// 若所有方法都被过滤,直接终止注册(可选:根据业务决定是否保留服务注册)
log.info("【过滤提示】服务 {} 所有方法均被过滤,终止注册", url.getServiceInterface());
// log.info("【过滤提示】服务 {} 所有方法均被过滤,终止注册", url.getServiceInterface());
return;
} else {
// 替换 URL 中的 methods 参数为过滤后的列表
url = url.addParameter("methods", String.join(",", filteredMethods));
log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), filteredMethods);
// log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), filteredMethods);
}
}

View File

@@ -1,5 +1,6 @@
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;
@@ -17,8 +18,24 @@ public class MybatisFlexConfig {
//设置 SQL 审计收集器
AuditManager.setMessageCollector(auditMessage ->
log.info("[sql] time: {}, size: {}, sql:\n{}",
auditMessage.getElapsedTime(), auditMessage.getQueryCount(), auditMessage.getFullSql())
);
auditMessage.getElapsedTime(), auditMessage.getQueryCount(), compressSql(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

@@ -131,7 +131,7 @@ public class RabbitPublisher {
}
/**
* 订单商品状态消息
* 进件
*/
public void sendEntryManagerMsg(String shopId) {
sendMsg(RabbitConstants.Queue.SHOP_ENTRY_MANAGER, shopId);

View File

@@ -6,14 +6,15 @@ import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author GYJoker
@@ -650,4 +651,106 @@ public class RedisService {
}
return JSON.parseArray(jsonStr, type);
}
public static int retryCount = 5;
/**
* 执行任务并保证锁唯一
*
* @param supplier 业务逻辑
* @param lockKey Redis锁的Key
* @return 业务逻辑返回值
*/
public <T> T runFunAndCheckKey(Supplier<T> supplier, String lockKey) {
String lockValue = String.valueOf(System.nanoTime() + Thread.currentThread().threadId());
try {
// 尝试获取锁,超时时间 5 秒,防止死锁
boolean lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS));
int count = 0;
// 初始等待 10ms
int retryDelay = 10;
while (!lock) {
// 最多重试 10 次,大约 10 秒
if (count++ > 50) {
throw new RuntimeException("系统繁忙, 稍后再试");
}
Thread.sleep(retryDelay);
// 指数退避,最大等待 200ms
retryDelay = Math.min(retryDelay * 2, 200);
lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS));
}
// 执行任务
return supplier.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("线程被中断", e);
} catch (Exception e) {
log.error("执行出错:{}", e.getMessage(), e);
throw e;
} finally {
// 释放锁(使用 Lua 脚本确保原子性)
unlock(lockKey, lockValue);
}
}
/**
* 使用 Lua 脚本确保释放锁的原子性
*
* @param lockKey 锁的 Key
* @param lockValue 当前线程的锁值
*/
private void unlock(String lockKey, String lockValue) {
String luaScript =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
redisTemplate.execute(new DefaultRedisScript<>(luaScript, Long.class),
Collections.singletonList(lockKey), lockValue);
}
public static <T, R> R runFunAndRetry(
Supplier<R> function,
Function<R, Boolean> check, Consumer<R> errFun) {
R result = function.get();
boolean flag = check.apply(result);
while (flag && retryCount-- > 0) {
result = function.get();
flag = check.apply(result);
}
if (flag) {
errFun.accept(result);
}
return result;
}
/**
* 防抖函数:在指定秒数内相同 Key 的任务只会执行一次
*
* @param key 防抖使用的 Redis Key
* @param seconds 防抖时间(秒)
* @param task 要执行的业务逻辑
* @return true 执行了任务false 在防抖期内被拦截
*/
public boolean debounce(String key, long seconds, Runnable task) {
try {
Boolean success = redisTemplate.opsForValue().setIfAbsent(
key, "1", seconds, TimeUnit.SECONDS
);
if (Boolean.TRUE.equals(success)) {
task.run();
return true;
}
return false;
} catch (Exception e) {
log.error("防抖函数执行失败 key={} err={}", key, e.getMessage(), e);
return false;
}
}
}

View File

@@ -285,4 +285,13 @@ public class ShopInfoEditDTO {
*/
private Integer isCountStick;
/**
* 企业id
*/
private String weworkId;
/**
* 企业接入链接
*/
private String weworkUrl;
}

View File

@@ -0,0 +1,69 @@
package com.czg.account.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 悬浮窗配置 实体类。
*
* @author ww
* @since 2025-12-29
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_quick_menu")
public class QuickMenu implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Integer id;
/**
* 店铺Id
*/
private Long shopId;
/**
* 菜单图标
*/
private String url;
/**
* 菜单Id
*/
@NotNull(message = "关联菜单不能为空")
private Long menuId;
/**
* 排序
*/
private Integer sort;
/**
* 状态 1-启用 0-禁用
*/
private Integer status;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -135,5 +135,13 @@ public class ShopConfig implements Serializable {
private String dingAppKey;
private String dingAppSecret;
/**
* 企业id
*/
private String weworkId;
/**
* 企业接入链接
*/
private String weworkUrl;
}

View File

@@ -32,7 +32,6 @@ public class ShopInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 使用系统用户 sys_user id
*/
@@ -142,14 +141,6 @@ public class ShopInfo implements Serializable {
* -1 平台禁用 0-过期1正式营业
*/
private Integer status;
/**
* 微信商户id
*/
private String wechatMerchantId;
/**
* 支付宝商户id
*/
private String alipayMerchantId;
/**
* 到期时间
@@ -371,4 +362,15 @@ public class ShopInfo implements Serializable {
*/
private BigDecimal amount;
/**
* 企业id
*/
@Column(ignore = true)
private String weworkId;
/**
* 企业接入链接
*/
@Column(ignore = true)
private String weworkUrl;
}

View File

@@ -0,0 +1,14 @@
package com.czg.account.service;
import com.mybatisflex.core.service.IService;
import com.czg.account.entity.QuickMenu;
/**
* 悬浮窗配置 服务层。
*
* @author ww
* @since 2025-12-29
*/
public interface QuickMenuService extends IService<QuickMenu> {
}

View File

@@ -23,8 +23,9 @@ public interface ShopInfoService extends IService<ShopInfo> {
/**
* 检测开关
* @param shopId 店铺id
* @param switchType ShopInfo的某列 开关 目前只支持Integer类型字段
*
* @param shopId 店铺id
* @param switchType ShopInfo的某列 开关 目前只支持Integer类型字段
* @return true:开启 false:关闭
*/
boolean checkSwitch(Long shopId, ShopSwitchTypeEnum switchType) throws ValidateException;
@@ -37,11 +38,6 @@ public interface ShopInfoService extends IService<ShopInfo> {
Boolean edit(ShopInfoEditDTO shopInfoEditDTO);
/**
* 进件结果保存
*/
Boolean editEntry(Long shopId, String wechatMerchantId, String alipayMerchantId);
ShopDetailDTO detail(Long id) throws CzgException;
ShopInfoByCodeDTO getByCode(String tableCode, String lat, String lng, boolean checkState);

View File

@@ -1,22 +0,0 @@
package com.czg.account.service;
import com.czg.account.dto.merchant.ShopMerchantEditDTO;
import com.czg.account.entity.ShopMerchant;
import com.mybatisflex.core.service.IService;
import java.io.Serializable;
/**
* 第三方商户进件 服务层。
*
* @author Administrator
* @since 2025-02-11
*/
public interface ShopMerchantService extends IService<ShopMerchant> {
ShopMerchant detail(Integer shopId);
Boolean edit(ShopMerchantEditDTO shopMerchantEditDTO);
@Override
ShopMerchant getById(Serializable id);
}

View File

@@ -79,7 +79,9 @@ public interface ParamCodeCst {
* 超掌柜支付回调地址
* <p>支付宝/微信支付完成后,支付平台回调我方系统的地址</p>
*/
public static String PAY_CZG_NOTIFY_URL = "pay_czg_notify_url";
// public static String PAY_CZG_NOTIFY_URL = "pay_czg_notify_url";
public static String NATIVE_PAY_NOTIFY_URL = "native_pay_notify_url";
public static String POLY_PAY_NOTIFY_URL = "poly_pay_notify_url";
/**
* 排队到号通知
*/

View File

@@ -7,10 +7,12 @@ 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;
@@ -123,6 +125,8 @@ public interface MkDistributionUserService extends IService<MkDistributionUser>
void refund(Long orderId, String orderNo);
void distributionUserAmount(MkDistributionFlow item, OrderInfo orderInfo);
/**
* 发放分销奖励
*

View File

@@ -28,6 +28,7 @@ public class OrderInfoAddDTO implements Serializable {
* 已出菜 SENT_OUT
* 已上菜 DELIVERED
* 已超时 EXPIRED
* 加急 URGENT
*/
private String subStatus;
//限时折扣部分

View File

@@ -1,267 +0,0 @@
package com.czg.order.dto;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import com.alibaba.fastjson2.annotation.JSONField;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 订单表 实体类。
*
* @author ww
* @since 2025-02-13
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderInfoDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
/**
* 订单编号
* pc 收银机客户端 PC+雪花ID
* wechat 微信小程序 WX+雪花ID
* alipay 支付宝小程序 ALI+雪花ID
* admin-pc PC管理端 WEB+雪花ID
* admin-app APP管理端 APP+雪花ID
*/
private String orderNo;
/**
* 店铺Id
*/
private Long shopId;
/**
* 用户Id user_info表的id
*/
private Long userId;
/**
* 退单金额
*/
private BigDecimal refundAmount;
/**
* 订单原金额 不含折扣价格
*/
private BigDecimal originAmount;
/**
* 抹零金额 减免多少钱
*/
private BigDecimal roundAmount;
/**
* 优惠总金额
*/
private BigDecimal discountAllAmount;
/**
* 订单金额 (扣除各类折扣)
*/
private BigDecimal orderAmount;
/**
* 实际支付金额
*/
private BigDecimal payAmount;
/**
* 积分抵扣金额
*/
private BigDecimal pointsDiscountAmount;
/**
* 使用的积分数量
*/
private Integer pointsNum;
/**
* 商品优惠券抵扣金额
*/
private BigDecimal productCouponDiscountAmount;
/**
* 用户使用的卡券
*/
private String couponInfoList;
/**
* 满减活动抵扣金额
*/
private BigDecimal discountActAmount;
/**
* 折扣金额
*/
private BigDecimal discountAmount;
// /**
// * 折扣比例
// */
// private BigDecimal discountRatio;
/**
* 打包费
*/
private BigDecimal packFee;
/**
* 台桌Id
*/
private String tableCode;
/**
* 台桌名称
*/
private String tableName;
/**
* 订单类型-
* cash收银(除小程序以外 都属于收银)
* miniapp小程序
*/
private String orderType;
/**
* 平台类型 pc 收银机客户端 wechat 微信小程序 alipay 支付宝小程序 admin-pc PC管理端 admin-app APP管理端
*/
private String platformType;
/**
* 用餐模式 堂食 dine-in 外带 take-out 外卖 take-away
*/
private String dineMode;
/**
* 支付模式:
* 后付费 after-pay
* 先付费 before-pay
* 无桌码 no-table
*/
private String payMode;
/**
* 支付类型
* 主扫 main-scan
* 被扫 back-scan
* 微信小程序 wechat-mini
* 支付宝小程序 alipay-mini
* 会员支付 vip-pay
* 现金支付 cash-pay
*/
private String payType;
/**
* 状态: unpaid-待支付;in-production 制作中;wait_out 待取餐;;done-订单完成;refunding-申请退单;refund-退单;part_refund 部分退单;cancelled-取消订单
*/
private String status;
/**
* 折扣信息 json
*/
private String discountInfo;
/**
* 限时折扣信息 json
*/
private String limitRate;
/**
* 是否支持退款1支持退单 0不支持退单
*/
private Integer refundAble;
/**
* 支付时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime paidTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 支付订单号
* tb_order_payment.id
* tb_shop_user_flow.id
*/
private Long payOrderId;
/**
* 交易日期
*/
private String tradeDay;
/**
* 备注
*/
private String remark;
/**
* 取餐码
*/
private String takeCode;
/**
* 员工id
*/
private Long staffId;
/**
* 当前订单下单次数
*/
private Integer placeNum;
/**
* 用餐人数
*/
private Integer seatNum;
/**
* 餐位费
*/
private BigDecimal seatAmount;
/**
* 退款备注
*/
private String refundRemark;
/**
* 是否使用了霸王餐
*/
private Integer isFreeDine;
/**
* 是否等叫 0 否 1 等叫
*/
private Integer isWaitCall;
/**
* 挂账人id
*/
private Long creditBuyerId;
/**
* 是否回收站 0-否1回收站
*/
private Integer isDel;
private String failMsg;
}

View File

@@ -0,0 +1,40 @@
package com.czg.order.dto;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.pay.NativeMerchantDTO;
import com.czg.pay.PolyMerchantDTO;
import lombok.Data;
/**
* 支付信息
*
* @author ww
*/
@Data
public class ShopMerchantDTO {
private Long shopId;
/**
* poly 聚合(支付平台) native 原生(wx/ali 原生)
* {@link com.czg.constant.PayChannelCst}
*/
private String channel;
/**
* 聚合支付商户
* native 必填 对应 tb_shop_direct_merchant 的 licence_no 营业执照
*/
private String relatedLicenceNo;
/**
* 原生支付参数
*/
private NativeMerchantDTO nativeMerchantDTO;
/**
* 聚合支付参数
*/
private PolyMerchantDTO polyMerchantDTO;
/**
* 店铺绑定的商户信息
*/
private ShopDirectMerchant shopDirectMerchant;
}

View File

@@ -1,6 +1,8 @@
package com.czg.order.entity;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.order.dto.LimitRateDTO;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
@@ -298,8 +300,10 @@ public class OrderInfo implements Serializable {
private Integer isDel;
private String failMsg;
/**
* 打印状态 Json格式
*/
private String printStatus;
public String getRefundRemark() {
@@ -342,4 +346,41 @@ public class OrderInfo implements Serializable {
// 如果需要加上抹零金额,可以取消下面这行注释
// .add(this.getRoundAmount() != null ? this.getRoundAmount() : BigDecimal.ZERO);
}
private JSONArray getPrintStatusAsArray() {
if (StrUtil.isBlank(printStatus)) {
return new JSONArray();
}
try {
return JSONArray.parseArray(printStatus.trim());
} catch (Exception e) {
return new JSONArray();
}
}
public void upPrintStatus(JSONObject printJson, boolean isPrintSuccess) {
String currentDeviceId = printJson.getString("id");
JSONArray oldPrintStatusArray = getPrintStatusAsArray();
// 3. 初始化新的打印状态JSON数组用于存储处理后的结果
JSONArray newPrintStatusArray = new JSONArray();
// 场景1打印成功 - 移除原有数组中与当前设备ID一致的记录保留其余记录
if (oldPrintStatusArray != null && !oldPrintStatusArray.isEmpty()) {
for (int i = 0; i < oldPrintStatusArray.size(); i++) {
JSONObject deviceObj = oldPrintStatusArray.getJSONObject(i);
String deviceId = deviceObj.getString("id");
// 仅保留非当前设备ID的记录
if (currentDeviceId != null && !currentDeviceId.equals(deviceId)) {
newPrintStatusArray.add(deviceObj);
}
}
}
if (!isPrintSuccess) {
newPrintStatusArray.add(printJson);
}
if (!newPrintStatusArray.isEmpty()) {
printStatus = newPrintStatusArray.toJSONString();
} else {
printStatus = "";
}
}
}

View File

@@ -5,6 +5,7 @@ import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -40,6 +41,12 @@ public class OrderPayment implements Serializable {
*/
private Long shopId;
/**
* 支付渠道
* {@link com.czg.constant.PayChannelCst}
*/
private String channel;
/**
* 来源Id 订单Id或充值id
*/
@@ -104,28 +111,66 @@ public class OrderPayment implements Serializable {
public OrderPayment() {
}
public OrderPayment(@NonNull Long shopId,@NonNull Long sourceId, @NotBlank String sourceType,@NotBlank String payType, @NotBlank String orderNo,
String authCode, @NonNull BigDecimal amount) {
this.shopId = shopId;
this.sourceId = sourceId;
this.sourceType = sourceType;
this.payType = payType;
this.orderNo = orderNo;
this.authCode = authCode;
this.amount = amount;
this.payStatus = PayTypeConstants.PayStatus.INIT;
/**
* 订单专用支付
*
* @param sourceId 订单Id
* @param amount 单元 元
* @param authCode 扫码支付时必填 扫描码
*/
public static OrderPayment orderPay(@NonNull Long shopId, @NonNull Long sourceId,
@NotBlank String orderNo, @NonNull BigDecimal amount, String authCode) {
OrderPayment orderPayment = getInstance(shopId, sourceId, PayTypeConstants.SourceType.ORDER, orderNo, amount, authCode, null);
orderPayment.setPayType(PayTypeConstants.PayType.PAY);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
public OrderPayment(@NonNull Long shopId,@NonNull Long sourceId, @NotBlank String sourceType,@NotBlank String payType, @NotBlank String orderNo,
String authCode, @NonNull BigDecimal amount, Long relatedId) {
this.shopId = shopId;
this.sourceId = sourceId;
this.sourceType = sourceType;
this.payType = payType;
this.orderNo = orderNo;
this.authCode = authCode;
this.amount = amount;
this.relatedId = relatedId;
this.payStatus = PayTypeConstants.PayStatus.INIT;
/**
* 初始化支付参数
*
* @param sourceId 充值时为会员Id shopUserID
* 购买时为商品Id
* @param sourceType {@link PayTypeConstants.SourceType} 支付来源
* @param amount 单元 元
* @param authCode 扫码支付时必填 扫描码
* @param relatedId 霸王餐充值为 订单id 会员充值为 活动id 充值并支付时 为 MkShopRechargeDetail
*/
public static OrderPayment pay(@NonNull Long shopId, @NonNull Long sourceId, @NotBlank String sourceType,
@NotBlank String orderNo, @NonNull BigDecimal amount,
String authCode, Long relatedId) {
OrderPayment orderPayment = getInstance(shopId, sourceId, sourceType, orderNo, amount, authCode, relatedId);
orderPayment.setPayType(PayTypeConstants.PayType.PAY);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
public static OrderPayment refund(@NonNull Long shopId, @NonNull Long sourceId, @NotBlank String sourceType,
@NotBlank String orderNo, @NonNull BigDecimal amount, Long relatedId) {
OrderPayment orderPayment = getInstance(shopId, sourceId, sourceType, orderNo, amount, null, relatedId);
orderPayment.setPayType(PayTypeConstants.PayType.REFUND);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
public static OrderPayment refundCompensate(@NonNull Long shopId, @NonNull Long sourceId, @NotBlank String sourceType,
@NotBlank String orderNo, @NonNull BigDecimal amount, Long relatedId) {
OrderPayment orderPayment = getInstance(shopId, sourceId, sourceType, orderNo, amount, null, relatedId);
orderPayment.setPayType(PayTypeConstants.PayType.REFUND_COMPENSATE);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
private static OrderPayment getInstance(Long shopId, Long sourceId, String sourceType,
String orderNo, BigDecimal amount, String authCode, Long relatedId) {
OrderPayment orderPayment = new OrderPayment();
orderPayment.shopId = shopId;
orderPayment.sourceId = sourceId;
orderPayment.sourceType = sourceType;
orderPayment.orderNo = orderNo;
orderPayment.authCode = authCode;
orderPayment.amount = amount;
orderPayment.relatedId = relatedId;
return orderPayment;
}
}

View File

@@ -35,6 +35,11 @@ public class ShopDirectMerchant implements Serializable {
*/
@Id
private Long shopId;
/**
* 店铺名称
*/
@Column(ignore = true)
private String shopName;
/**
* 营业执照编号
@@ -44,12 +49,24 @@ public class ShopDirectMerchant implements Serializable {
* 支付宝账号
*/
private String alipayAccount;
/**
* 商户编号(在当前系统唯一)
*/
private String merchantCode;
/**
* 【必填】
* 商户类型
* 0: 个体商户;
* 1: 企业商户;
* 3: 小微商户 暂不支持
*/
private String userType;
/**
* 【必填】
* 商户简称--企业、个体必填
*/
private String shortName;
/**
* 商户基础信息
*/
@@ -115,4 +132,18 @@ public class ShopDirectMerchant implements Serializable {
*/
private String alipaySignUrl;
/**
* 支付宝授信息
*/
private String alipayAuthInfo;
/**
* 微信商户id
*/
private String wechatMerchantId;
/**
* 支付宝商户id
*/
private String alipayMerchantId;
}

View File

@@ -1,4 +1,4 @@
package com.czg.account.entity;
package com.czg.order.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
@@ -18,57 +18,45 @@ import java.time.LocalDateTime;
* @since 2025-02-11
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_shop_merchant")
@Table("tb_shop_merchant2")
public class ShopMerchant implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id
private Long id;
/**
* 店铺id
*/
@Id
private Long shopId;
/**
* 支付系统商户id
* poly 聚合(支付平台) native 原生(wx/ali 原生)
* {@link com.czg.constant.PayChannelCst}
*/
private String storeId;
private String merchantName;
private String channel;
/**
* 商户应用id
* 聚合支付商户
* native 必填 对应 tb_shop_direct_merchant licence_no 营业执照
*/
private String appId;
private String relatedLicenceNo;
/**
* 商户token
* 聚合支付参数
*/
private String appSecret;
private String polyPayJson;
/**
* 微信小程序appid
* 原生支付参数
*/
private String wechatSmallAppid;
/**
* 支付宝小程序appid
*/
private String alipaySmallAppid;
/**
* 支付密码
*/
private String payPassword;
private String nativePayJson;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -11,6 +11,8 @@ import com.czg.order.entity.PrintMachineLog;
* @since 2025-03-11
*/
public interface PrintMachineLogService extends IService<PrintMachineLog> {
void save(PrintMachine config, String bizType, String printContent, Object respJson);
void save(Long orderId, PrintMachine config, String bizType, String printContent, String respJson);
void save(PrintMachine config, String bizType, String printContent, String respJson);
}

View File

@@ -0,0 +1,30 @@
package com.czg.order.service;
import com.czg.order.dto.ShopMerchantDTO;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.order.entity.ShopMerchant;
import com.mybatisflex.core.service.IService;
import java.io.Serializable;
/**
* 第三方商户进件 服务层。
*
* @author Administrator
* @since 2025-02-11
*/
public interface ShopMerchantService extends IService<ShopMerchant> {
ShopMerchantDTO detail(Long shopId);
/**
* 进件结果保存/ 支付参数修改
*/
Boolean editEntry(ShopMerchantDTO shopMerchantParam, boolean isUp);
@Override
ShopMerchant getById(Serializable id);
ShopDirectMerchant getMainMerchant(Long shopId);
}

View File

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

View File

@@ -133,6 +133,11 @@ public class OrderInfoVo implements Serializable {
* 备注
*/
private String remark;
/**
* 打印状态 Json格式
* [{"id":"124","name":"111","time":"2025-12-29 11:05:18"},{"id":"111","name":"标签","time":"2025-12-29 11:05:30"}]
*/
private String printStatus;
/**
* 是否使用了霸王餐

View File

@@ -0,0 +1,63 @@
package com.czg.pay;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 支付宝授权信息
* @author yjjie
* @date 2026/1/9 11:31
*/
@Data
@Accessors(chain = true)
public class AlipayAuthInfoDto {
/**
* 授权商户的user_id
*/
@JSONField(name = "user_id")
private String userId;
/**
* 授权商户的open_id
*/
@JSONField(name = "open_id")
private String openId;
/**
* 授权商户的appid
*/
@JSONField(name = "auth_app_id")
private String authAppId;
/**
* 应用授权令牌
*/
@JSONField(name = "app_auth_token")
private String appAuthToken;
/**
* 应用授权令牌有效期
*/
@JSONField(name = "expires_in")
private String expiresIn;
/**
* 刷新令牌
*/
@JSONField(name = "app_refresh_token")
private String appRefreshToken;
/**
* 刷新令牌的有效时间
*/
@JSONField(name = "re_expires_in")
private String reExpiresIn;
/**
* 签约单号
*/
@JSONField(name = "order_no")
private String orderNo;
}

View File

@@ -0,0 +1,132 @@
package com.czg.pay;
import lombok.Data;
import lombok.NonNull;
/**
* @author ww
*/
@Data
public class CzgPayBaseReq<T> {
//必填范围
/**
* 订单标题
*/
private String subject;
/**
* 订单描述 String(256)
*/
private String body;
/**
* 交易金额 分
*/
private Long amount;
/**
* 货币类型 cny
*/
private String currency = "cny";
/**
* 商户订单号 String(30)
* 操作方式+雪花算法
* 收银机客户端 PC+雪花ID
* 微信小程序 WX+雪花ID
* 支付宝小程序 ALI+雪花ID
* PC管理端 WEB+雪花ID
* APP管理端 APP+雪花ID
* <p>
* 退款 re+雪花ID
*/
private String mchOrderNo;
/**
* 异步通知地址 String(128)
* 支付结果异步回调URL,只有传了该值才会发起回调
*/
private String notifyUrl;
/**
* 扩展参数 String(512)
* 商户扩展参数,回调时会原样返回
* * 扩展参数
* * {
* * "pay_type": "order/vip"
* * }
*/
private String extParam;
/**
* 原生支付 不需要 store_id
*/
private String storeId;
/**
* 支付类型
*/
private String payType;
/**
* 用户唯一标识 String(30)
* 微信支付时传入用户的openId
* 支付宝支付和银联支付时传入用户的userId
*/
private String userId;
/**
* 用户IP
* 需要传付款用户客户端IP地址
*/
private String clientIp;
/**
* 子商户 appid ,微信付款支付的时候 需要上送
* isScreen 为 false 的情况下需要传入
*/
private String subAppid;
/**
* 额外参数
*/
private T data;
public CzgPayBaseReq() {
}
public CzgPayBaseReq(String mchOrderNo, String detail, Long amount, String payType, String userId, String clientIp) {
this.mchOrderNo = mchOrderNo;
this.subject = detail;
this.body = detail;
this.amount = amount;
this.payType = payType;
this.userId = userId;
this.clientIp = clientIp;
}
public void polyBase(@NonNull String storeId, @NonNull String notifyUrl) {
this.storeId = storeId;
this.notifyUrl = notifyUrl;
}
public static CzgPayBaseReq<?> ltPayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount
, @NonNull String payType, @NonNull String openId, @NonNull String clientIp) {
return new CzgPayBaseReq<>(mchOrderNo, detail, amount, payType, openId, clientIp);
}
public static CzgPayBaseReq<?> h5PayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount, @NonNull String clientIp) {
return new CzgPayBaseReq<>(mchOrderNo, detail, amount, null, null, clientIp);
}
public static CzgPayBaseReq<?> jsPayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount
, @NonNull String payType, @NonNull String openId, @NonNull String clientIp) {
return new CzgPayBaseReq<>(mchOrderNo, detail, amount, payType, openId, clientIp);
}
public static CzgPayBaseReq<?> scanPayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount, @NonNull String clientIp) {
return new CzgPayBaseReq<>(mchOrderNo, detail, amount, null, null, clientIp);
}
public static CzgPayBaseReq<String> microPay(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount, @NonNull String authCode) {
CzgPayBaseReq<String> stringReq = new CzgPayBaseReq<>(mchOrderNo, detail, amount, null, null, null);
stringReq.setData(authCode);
return stringReq;
}
}

View File

@@ -1,4 +1,4 @@
package com.czg.entity.req;
package com.czg.pay;
import lombok.Data;
import lombok.NonNull;
@@ -23,7 +23,10 @@ public class CzgRefundReq {
* 单位为分
*/
private Long refundAmount;
/**
* 原订单总金额 单位
*/
private Long orderTotalAmount;
//非必填范围
/**
@@ -51,10 +54,11 @@ public class CzgRefundReq {
* payOrderId和mchOrderNo 二选一 必填
*/
public CzgRefundReq(@NonNull String mchRefundNo, @NonNull String refundReason, @NonNull Long refundAmount,
String mchOrderNo, String extParam) {
@NonNull Long orderTotalAmount, String mchOrderNo, String extParam) {
this.mchRefundNo = mchRefundNo;
this.refundReason = refundReason;
this.refundAmount = refundAmount;
this.orderTotalAmount = orderTotalAmount;
this.mchOrderNo = mchOrderNo;
this.extParam = extParam;
}

View File

@@ -0,0 +1,17 @@
package com.czg.pay;
import lombok.Data;
/**
* 原生支付参数
* @author ww
*/
@Data
public class NativeMerchantDTO {
private String wechatMerchantId;
private String alipayMerchantId;
/**
* 支付宝 授权信息解析
*/
private AlipayAuthInfoDto alipayAuthInfo;
}

View File

@@ -1,16 +1,14 @@
package com.czg.account.dto.merchant;
package com.czg.pay;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author Administrator
* 聚合支付参数
* @author ww
*/
@Data
public class ShopMerchantEditDTO {
@NotNull(message = "店铺id不为空")
private Long shopId;
public class PolyMerchantDTO {
@NotEmpty(message = "支付系统商户id不为空")
private String storeId;
@NotEmpty(message = "支付系统商户名称不为空")

View File

@@ -58,7 +58,7 @@ public class SysBankInfo implements Serializable {
private String bankAliasCode;
/**
* 不知道干啥的
* 是否需要支行信息
*/
private Boolean needBankBranch;

View File

@@ -60,6 +60,10 @@ public class SysRegion implements Serializable {
* 全级别名称(如“中国|北京|北京市|东城区)
*/
private String fullName;
/**
* 微信区域编码
*/
private String wxProvinceCode;
/**
* 子级区域

View File

@@ -0,0 +1,18 @@
package com.czg.constant;
/**
* 支付渠道常量
* @author ww
*/
public interface PayChannelCst {
/**
* 聚合支付
* 对应 类 PolyPay
*/
String POLY = "poly";
/**
* 原生支付
* 对应 类 NativePay
*/
String NATIVE = "native";
}

View File

@@ -2,11 +2,9 @@ package com.czg;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.dto.req.*;
import com.czg.dto.resp.BankBranchDto;
import com.czg.dto.resp.EntryRespDto;
import com.czg.dto.resp.EntryThirdRespDto;
import com.czg.dto.resp.QueryStatusResp;
import com.czg.dto.resp.*;
import com.czg.exception.CzgException;
import com.czg.third.alipay.AlipayEntryManager;
import com.czg.third.alipay.AlipayIsvEntryManager;
@@ -38,6 +36,17 @@ public class EntryManager {
return AlipayEntryManager.queryBankBranchList(null, instId, province, city);
}
/**
* 查询银行支行列表
* 走微信查询
*
* @param bankAliceCode 银行代码
* @param cityCode 城市编码
*/
public static WechatBankBranchRespDto queryBankBranchList(String bankAliceCode, String cityCode) {
return WechatEntryManager.queryBankBranchList(null, bankAliceCode, cityCode, 0, 200);
}
/**
* 查询微信进件状态
*
@@ -101,6 +110,7 @@ public class EntryManager {
entryRespDto.setAlipayOrderId(respDto.getEntryId());
entryRespDto.setAlipayStatus(respDto.getStatus());
entryRespDto.setAlipayErrorMsg(respDto.getErrorMsg());
entryRespDto.setAlipayAuthInfo(respDto.getAlipayAuthInfo());
}
}
return entryRespDto;
@@ -215,10 +225,10 @@ public class EntryManager {
String image = WechatEntryManager.uploadImage(null, dto.getUrl());
dto.setWechatId(image);
}
if (StrUtil.isBlank(dto.getAlipayId())) {
String image = AlipayEntryManager.uploadImage(null, dto.getUrl());
dto.setAlipayId(image);
}
// if (StrUtil.isBlank(dto.getAlipayId())) {
// String image = AlipayEntryManager.uploadImage(null, dto.getUrl());
// dto.setAlipayId(image);
// }
}
}
@@ -362,99 +372,121 @@ public class EntryManager {
public static void main(String[] args) {
// WechatBankBranchRespDto respDto = queryBankBranchList("1000009547", "931");
// System.out.println(respDto);
AggregateMerchantDto merchantDto = getTestMerchantEntryData();
//
verifyEntryParam(merchantDto);
uploadParamImage(merchantDto);
//
// verifyEntryParam(merchantDto);
// uploadParamImage(merchantDto);
verifyEntryParam(merchantDto);
// uploadParamImage(merchantDto);
// System.out.println(merchantDto);
// entryMerchant(merchantDto, PayCst.Platform.WECHAT);
entryMerchant(merchantDto, PayCst.Platform.ALIPAY);
//// System.out.println(merchantDto);
EntryRespDto respDto = entryMerchant(merchantDto, PayCst.Platform.WECHAT);
// entryMerchant(merchantDto, PayCst.Platform.ALIPAY);
// entryMerchant(merchantDto, PayCst.Platform.WECHAT, PayCst.Platform.ALIPAY);
System.out.println(respDto);
}
private static AggregateMerchantDto getTestMerchantEntryData() {
AggregateMerchantDto merchantDto = new AggregateMerchantDto();
merchantDto.setMerchantCode("20220106000000000001");
merchantDto.setMerchantCode("CZG20260112151202011");
MerchantBaseInfoDto baseInfoDto = new MerchantBaseInfoDto();
baseInfoDto.setUserType("1");
baseInfoDto.setCompanyChildType("1");
baseInfoDto.setShortName("测试商户");
baseInfoDto.setAlipayAccount("1157756119@qq.com");
baseInfoDto.setMccCode("A0001_B0001");
baseInfoDto.setContactPersonType(PayCst.ContactPersonType.SUPER);
baseInfoDto.setContactName("张三");
baseInfoDto.setContactPersonId("110101199001011234");
baseInfoDto.setContactPersonIdStartDate("2021-01-01");
baseInfoDto.setContactPersonIdEndDate("2025-01-01");
baseInfoDto.setContactPhone("13800000000");
baseInfoDto.setContactEmail("1157756119@qq.com");
baseInfoDto.setContactAddr("广东省深圳市南山区");
baseInfoDto.setContactIdCardFrontPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
baseInfoDto.setContactIdCardBackPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
merchantDto.setMerchantBaseInfo(baseInfoDto);
String baseInfo = "{\"alipayAccount\":\"18191655977\",\"certType\":\"0\",\"companyChildType\":\"1\",\"contactAddr\":\"西安市沣东新城石化大道西段106号沣东科技园5号楼1层5-037室\",\"contactEmail\":\"892675422@qq.com\",\"contactIdCardBackPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/ce731859ee644df8a4a46104b49c7696.png\",\"wechatId\":\"V1_S-iU_YpBpSKoSZFhQw3plh53G4PXHmNlhi1s88_VTk7A943tAxrkIcKErRcpFPkxG7vkMzhkT4ecN3IWxv71JwLJOzY9eQhmv6giwKWUAjk\"},\"contactIdCardFrontPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/e0d259f9fbcf4897b7f93f3f7d1b8e9a.png\",\"wechatId\":\"V1_oYXFrsrx4sZqiHXURjDBMB53G4PXHmPB0jH4yl2JSowqJDinBqRYIZmHrRcpFPkxsGFO-6Ci3dGvLAs-X2g2DQLJOzY9eQhmv6giwKWUAjk\"},\"contactName\":\"\",\"contactPersonId\":\"612501199212187875\",\"contactPersonIdEndDate\":\"2039-02-01\",\"contactPersonIdStartDate\":\"2019-02-01\",\"contactPersonType\":\"LEGAL\",\"contactPhone\":\"18191655977\",\"mccCode\":\"A0001_B0001\",\"shortName\":\"菲慕斯博\",\"userType\":\"1\"}";
merchantDto.setMerchantBaseInfo(JSONObject.parseObject(baseInfo, MerchantBaseInfoDto.class));
BusinessLicenceInfoDto businessLicenceInfoDto = new BusinessLicenceInfoDto();
businessLicenceInfoDto.setLicenceName("测试商户");
businessLicenceInfoDto.setLicenceNo("110101199001011234");
businessLicenceInfoDto.setLicenceStartDate("2021-01-01");
businessLicenceInfoDto.setLicenceEndDate("2052-01-01");
businessLicenceInfoDto.setRegisteredAddress("广东省深圳市南山区");
businessLicenceInfoDto.setLicensePic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
merchantDto.setBusinessLicenceInfo(businessLicenceInfoDto);
String legalPersonInfo = "{\"idCardBackPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/bb0f77b0b3404bbd9975a4f8497494df.png\",\"wechatId\":\"V1_Kt7wB6u_YhTp_V97CU_V_x53G4PXHmOeC1YpTSt8JenBIbhCzXjNIZWHrRcpFPkxHwsAu6WQfWU6BYJ3glMBnALJOzY9eQhmv6giwKWUAjk\"},\"idCardFrontPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/196a6f37c5954fc395d621e5b0289cb5.png\",\"wechatId\":\"V1__G9UoJplQHSY_ychzdk7QR53G4PXHmMm845pnkw_19i0CeVtQ34dIbOHrRcpFPkxsIEMvoVq19SdOFHTsw6b3wLJOzY9eQhmv6giwKWUAjk\"},\"idCardHandPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/eaa5e0f9352d4e77bbf5fa133ed54564.jpg\",\"wechatId\":\"V1_mWQpc12PTPL7P7kkdUOR6h53G4PXHmPbBEOZTTwh_KJ8RdecGr9kIZuGrRcpFPkx-jdQCaZuUWIQRmxr8pm-7QLJOzY9eQhmv6giwKWUAjk\"},\"legalAddress\":\"西安市沣东新城石化大道西段106号沣东科技园5号楼1层5-037室\",\"legalGender\":\"0\",\"legalIdPersonStartDate\":\"2019-02-01\",\"legalPersonEmail\":\"892675422@qq.com\",\"legalPersonId\":\"612501199212187875\",\"legalPersonIdEndDate\":\"2039-02-01\",\"legalPersonName\":\"蔺佳佳\",\"legalPersonPhone\":\"18191655977\"}";
merchantDto.setLegalPersonInfo(JSONObject.parseObject(legalPersonInfo, LegalPersonInfoDto.class));
LegalPersonInfoDto legalPersonInfoDto = new LegalPersonInfoDto();
legalPersonInfoDto.setLegalPersonName("张三");
legalPersonInfoDto.setLegalPersonId("110101199001011234");
legalPersonInfoDto.setLegalIdPersonStartDate("2021-01-01");
legalPersonInfoDto.setLegalPersonIdEndDate("2055-01-01");
legalPersonInfoDto.setLegalPersonPhone("13800000000");
legalPersonInfoDto.setLegalPersonEmail("1157756119@qq.com");
legalPersonInfoDto.setLegalGender("1");
legalPersonInfoDto.setLegalAddress("广东省深圳市南山区");
legalPersonInfoDto.setIdCardHandPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
legalPersonInfoDto.setIdCardFrontPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
legalPersonInfoDto.setIdCardBackPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
merchantDto.setLegalPersonInfo(legalPersonInfoDto);
String businessInfo = "{\"licenceEndDate\":\"2099-12-31\",\"licenceName\":\"西安菲慕斯博市场营销策划有限公司\",\"licenceNo\":\"91610131MA6TXACP28\",\"licenceStartDate\":\"2021-02-25\",\"licensePic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/81b60f3a25494c8586159a193389aa2d.jpg\",\"wechatId\":\"V1_-Vbealekn9NZb3mT37ggpB53G4PXHmNEw41rkFGHdR1KJkYqgc5QId-HrRcpFPkxJLlN6u4U4s24lzVyTVoxPgLJOzY9eQhmv6giwKWUAjk\"},\"registeredAddress\":\"陕西省西安市高新区科技路37号海星城市广场B座2002-080室\"}";
merchantDto.setBusinessLicenceInfo(JSONObject.parseObject(businessInfo, BusinessLicenceInfoDto.class));
StoreInfoDto storeInfoDto = new StoreInfoDto();
storeInfoDto.setMercProvCode("440000");
storeInfoDto.setMercCityCode("440300");
storeInfoDto.setMercAreaCode("440303");
storeInfoDto.setMercProv("广东省");
storeInfoDto.setMercCity("深圳市");
storeInfoDto.setMercArea("南山区");
storeInfoDto.setBusinessAddress("广东省深圳市南山区");
storeInfoDto.setInsidePic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
storeInfoDto.setDoorPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
storeInfoDto.setCashierDeskPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
merchantDto.setStoreInfo(storeInfoDto);
String storeInfo = "{\"businessAddress\":\"西安市沣东新城石化大道西段106号沣东科技园5号楼1层5-037室\",\"cashierDeskPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/4e52859aac754670aaf9be1c923da827.jpg\",\"wechatId\":\"V1_qFmvcdaX1XSUmknkcwKzMh53G4PXHmNYVJzGUiEs-qE-2ERQMr6XIemErRcpFPkxyCyY2DFU5QIBiaW6WamZmwLJOzY9eQhmv6giwKWUAjk\"},\"doorPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/2c207c6f4a764ad18e501ed10fbfad59.png\",\"wechatId\":\"V1_JPI6iQUmEXiUL2JogtdaJR53G4PXHmO3QpILvqWkLccmvi-vX4OJIdmBrRcpFPkxwNCa-m1w5XissHoA_ynwKQLJOzY9eQhmv6giwKWUAjk\"},\"insidePic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/394b4834698a47e9b75419a5fd7f7de7.jpg\",\"wechatId\":\"V1_djcTvjUKESKADtVCmtLqmR53G4PXHmOLw9uEV3te3o7OebPqjdklIdGBrRcpFPkxy6JbIGyYEZT6XatGXNQ2YQLJOzY9eQhmv6giwKWUAjk\"},\"mercArea\":\"雁塔区\",\"mercAreaCode\":\"610113\",\"mercCity\":\"西安市\",\"mercCityCode\":\"610100\",\"mercProv\":\"陕西省\",\"mercProvCode\":\"610000\"}";
merchantDto.setStoreInfo(JSONObject.parseObject(storeInfo, StoreInfoDto.class));
SettlementInfoDto settlementInfoDto = new SettlementInfoDto();
settlementInfoDto.setSettlementType("1");
settlementInfoDto.setSettlementCardType("21");
settlementInfoDto.setSettlementName("张三");
settlementInfoDto.setSettlementCardNo("110101199001011234");
settlementInfoDto.setBankMobile("13800000000");
settlementInfoDto.setOpenAccProvinceId("440000");
settlementInfoDto.setOpenAccCityId("440300");
settlementInfoDto.setOpenAccAreaId("440303");
settlementInfoDto.setOpenAccProvince("广东省");
settlementInfoDto.setOpenAccCity("深圳市");
settlementInfoDto.setOpenAccArea("南山区");
settlementInfoDto.setBankName("中国工商银行");
settlementInfoDto.setBankInstId("ICBC");
settlementInfoDto.setBankType("1");
settlementInfoDto.setBankBranchName("广东省深圳市南山区");
settlementInfoDto.setBankBranchCode("440300");
settlementInfoDto.setBankCardFrontPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
settlementInfoDto.setBankCardBackPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
settlementInfoDto.setOpenAccountLicencePic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
merchantDto.setSettlementInfo(settlementInfoDto);
String settlementInfo = "{\"bankBranchCode\":\"313791000427\",\"bankBranchName\":\"西安银行高新四路支行\",\"bankCardBackPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/3f3bb30f89fd4441985808f4a451c9c7.jpg\",\"wechatId\":\"V1_KAo5J49VNaCiC7twEi6NfB53G4PXHmNqgVl38ZojoETk3a9m_ZLvIaeHrRcpFPkxmQ3bRK2ytADSD8Fe8v-mpALJOzY9eQhmv6giwKWUAjk\"},\"bankCardFrontPic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/413f9170ca1d4f0893e05fd72b5e2b0e.jpg\",\"wechatId\":\"V1_GNhNtE1UYUCeRAuLsxdimR53G4PXHmNn9A4-gDbYgq47MiHxjki-IarByRcpFPkxfqldVa9taQ7W5KtWL35ppwLJOzY9eQhmv6giwKWUAjk\"},\"bankInstId\":\"XAB\",\"bankMobile\":\"18191655977\",\"bankName\":\"其他银行\",\"bankType\":\"\",\"noLegalHandSettleAuthPic\":{\"alipayId\":\"\",\"url\":\"\",\"wechatId\":\"\"},\"noLegalId\":\"\",\"noLegalIdCardBackPic\":{\"alipayId\":\"\",\"url\":\"\",\"wechatId\":\"\"},\"noLegalIdCardFrontPic\":{\"alipayId\":\"\",\"url\":\"\",\"wechatId\":\"\"},\"noLegalName\":\"\",\"noLegalSettleAuthPic\":{\"alipayId\":\"\",\"url\":\"\",\"wechatId\":\"\"},\"openAccArea\":\"雁塔区\",\"openAccAreaId\":\"610113\",\"openAccCity\":\"西安市\",\"openAccCityId\":\"610100\",\"openAccProvince\":\"陕西省\",\"openAccProvinceId\":\"610000\",\"openAccountLicencePic\":{\"alipayId\":\"\",\"url\":\"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/1/6e5dca0822f742649ecf1666f91ad1b3.jpg\",\"wechatId\":\"V1_1S62SpAFYecG5T-DC9ewHR53G4PXHmMA49fy0uVVk5j35lE5L5njIfSGrRcpFPkxU9Fm6P6bYLY3t010FYkmAQLJOzY9eQhmv6giwKWUAjk\"},\"settlementCardNo\":\"611011580000054186\",\"settlementCardType\":\"21\",\"settlementName\":\"西安菲慕斯博市场营销策划有限公司\",\"settlementType\":\"1\"}";
merchantDto.setSettlementInfo(JSONObject.parseObject(settlementInfo, SettlementInfoDto.class));
// merchantDto.setMerchantCode("20220106000000000001");
//
// MerchantBaseInfoDto baseInfoDto = new MerchantBaseInfoDto();
// baseInfoDto.setUserType("1");
// baseInfoDto.setCompanyChildType("1");
// baseInfoDto.setShortName("测试商户");
// baseInfoDto.setAlipayAccount("1157756119@qq.com");
// baseInfoDto.setMccCode("A0001_B0001");
// baseInfoDto.setContactPersonType(PayCst.ContactPersonType.SUPER);
// baseInfoDto.setContactName("张三");
// baseInfoDto.setContactPersonId("110101199001011234");
// baseInfoDto.setContactPersonIdStartDate("2021-01-01");
// baseInfoDto.setContactPersonIdEndDate("2025-01-01");
// baseInfoDto.setContactPhone("13800000000");
// baseInfoDto.setContactEmail("1157756119@qq.com");
// baseInfoDto.setContactAddr("广东省深圳市南山区");
// baseInfoDto.setContactIdCardFrontPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// baseInfoDto.setContactIdCardBackPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// merchantDto.setMerchantBaseInfo(baseInfoDto);
//
// BusinessLicenceInfoDto businessLicenceInfoDto = new BusinessLicenceInfoDto();
// businessLicenceInfoDto.setLicenceName("测试商户");
// businessLicenceInfoDto.setLicenceNo("110101199001011234");
// businessLicenceInfoDto.setLicenceStartDate("2021-01-01");
// businessLicenceInfoDto.setLicenceEndDate("2052-01-01");
// businessLicenceInfoDto.setRegisteredAddress("广东省深圳市南山区");
// businessLicenceInfoDto.setLicensePic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// merchantDto.setBusinessLicenceInfo(businessLicenceInfoDto);
//
// LegalPersonInfoDto legalPersonInfoDto = new LegalPersonInfoDto();
// legalPersonInfoDto.setLegalPersonName("张三");
// legalPersonInfoDto.setLegalPersonId("110101199001011234");
// legalPersonInfoDto.setLegalIdPersonStartDate("2021-01-01");
// legalPersonInfoDto.setLegalPersonIdEndDate("2055-01-01");
// legalPersonInfoDto.setLegalPersonPhone("13800000000");
// legalPersonInfoDto.setLegalPersonEmail("1157756119@qq.com");
// legalPersonInfoDto.setLegalGender("1");
// legalPersonInfoDto.setLegalAddress("广东省深圳市南山区");
// legalPersonInfoDto.setIdCardHandPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// legalPersonInfoDto.setIdCardFrontPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// legalPersonInfoDto.setIdCardBackPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// merchantDto.setLegalPersonInfo(legalPersonInfoDto);
//
// StoreInfoDto storeInfoDto = new StoreInfoDto();
// storeInfoDto.setMercProvCode("440000");
// storeInfoDto.setMercCityCode("440300");
// storeInfoDto.setMercAreaCode("440303");
// storeInfoDto.setMercProv("广东省");
// storeInfoDto.setMercCity("深圳市");
// storeInfoDto.setMercArea("南山区");
// storeInfoDto.setBusinessAddress("广东省深圳市南山区");
// storeInfoDto.setInsidePic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// storeInfoDto.setDoorPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// storeInfoDto.setCashierDeskPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// merchantDto.setStoreInfo(storeInfoDto);
//
// SettlementInfoDto settlementInfoDto = new SettlementInfoDto();
// settlementInfoDto.setSettlementType("1");
// settlementInfoDto.setSettlementCardType("21");
// settlementInfoDto.setSettlementName("张三");
// settlementInfoDto.setSettlementCardNo("110101199001011234");
// settlementInfoDto.setBankMobile("13800000000");
// settlementInfoDto.setOpenAccProvinceId("440000");
// settlementInfoDto.setOpenAccCityId("440300");
// settlementInfoDto.setOpenAccAreaId("440303");
// settlementInfoDto.setOpenAccProvince("广东省");
// settlementInfoDto.setOpenAccCity("深圳市");
// settlementInfoDto.setOpenAccArea("南山区");
// settlementInfoDto.setBankName("中国工商银行");
// settlementInfoDto.setBankInstId("ICBC");
// settlementInfoDto.setBankType("1");
// settlementInfoDto.setBankBranchName("广东省深圳市南山区");
// settlementInfoDto.setBankBranchCode("440300");
// settlementInfoDto.setBankCardFrontPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// settlementInfoDto.setBankCardBackPic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// settlementInfoDto.setOpenAccountLicencePic(new ImageDto("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg"));
// merchantDto.setSettlementInfo(settlementInfoDto);
return merchantDto;
}

View File

@@ -15,6 +15,11 @@ public interface PayCst {
*/
String LONG_TERM_DATE = "2099-12-31";
/**
* 支付宝异常信息获取 key
*/
String ALIPAY_ERROR_MSG_KEY = "message";
/**
* 平台
*/

View File

@@ -0,0 +1,103 @@
package com.czg;
import com.czg.dto.req.PayParamsDto;
import com.czg.dto.req.RefundParamsDto;
import com.czg.exception.CzgException;
import com.czg.third.alipay.AlipayIsvPayManager;
import com.czg.third.wechat.WechatPayManager;
import java.util.Map;
/**
* @author yjjie
* @date 2026/1/9 11:24
*/
public class PayManager {
/**
* jsapi支付
*
* @param paramsDto 参数
* @return 结果
*/
public static Map<String, Object> jsapiPay(PayParamsDto paramsDto) {
paramsDto.verifyParams();
if (PayCst.Platform.WECHAT.equals(paramsDto.getPlatform())) {
return WechatPayManager.jsapiPay(null, paramsDto);
} else if (PayCst.Platform.ALIPAY.equals(paramsDto.getPlatform())) {
return AlipayIsvPayManager.jsapiPay(null, paramsDto);
} else {
throw new CzgException("不支持的支付平台");
}
}
/**
* 条码支付
*
* @param paramsDto 参数
* @return 结果
*/
public static Map<String, Object> barPay(PayParamsDto paramsDto) {
paramsDto.verifyParams();
if (PayCst.Platform.WECHAT.equals(paramsDto.getPlatform())) {
return WechatPayManager.barPay(null, paramsDto);
} else if (PayCst.Platform.ALIPAY.equals(paramsDto.getPlatform())) {
return AlipayIsvPayManager.barPay(null, paramsDto);
} else {
throw new CzgException("不支持的支付平台");
}
}
/**
* 查询订单状态
*/
public static Map<String, Object> queryOrderStatus(String platform, String orderNo, String subMerchantId) {
if (PayCst.Platform.WECHAT.equals(platform)) {
return WechatPayManager.queryOrder(null, orderNo, subMerchantId);
} else if (PayCst.Platform.ALIPAY.equals(platform)) {
return AlipayIsvPayManager.queryOrder(null, orderNo, subMerchantId);
} else {
throw new CzgException("不支持的支付平台");
}
}
/**
* 退款
*/
public static Map<String, Object> refund(String platform, RefundParamsDto paramsDto) {
if (PayCst.Platform.WECHAT.equals(platform)) {
return WechatPayManager.refundOrder(null, paramsDto);
} else if (PayCst.Platform.ALIPAY.equals(platform)) {
return AlipayIsvPayManager.refundOrder(null, paramsDto);
} else {
throw new CzgException("不支持的支付平台");
}
}
public static void main(String[] args) {
// jsapiPay(new PayParamsDto()
// .setPlatform(PayCst.Platform.ALIPAY)
// .setAppId("2021004145625815")
// .setOpenId("123123123")
// .setOrderNo("1111231231213")
// .setTitle("1213")
// .setMerchantId("123312321")
// .setBody("1213")
// .setAmount(1000L)
// .setPayParams("{\"app_auth_token\": \"ssss\"}")
// .setNotifyUrl("https://www.baidu.com"));
jsapiPay(new PayParamsDto()
.setPlatform(PayCst.Platform.WECHAT)
.setAppId("wxd88fffa983758a30")
.setOpenId("or1l86yipGvwyfPhrKIAcQuSfAV8")
.setOrderNo("1111231231213")
.setTitle("1213")
.setMerchantId("1738216504")
.setBody("1213")
.setAmount(1000L)
.setPayParams("{\"app_auth_token\": \"ssss\"}")
.setNotifyUrl("https://www.baidu.com"));
}
}

View File

@@ -0,0 +1,120 @@
package com.czg.dto.req;
import com.alibaba.fastjson2.JSONObject;
import com.czg.PayCst;
import com.czg.exception.CzgException;
import com.czg.pay.AlipayAuthInfoDto;
import com.czg.utils.AssertUtil;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 支付参数
*
* @author yjjie
* @date 2026/1/9 11:12
*/
@Data
@Accessors(chain = true)
public class PayParamsDto {
/**
* 【必填】
* 支付方式
* {@link com.czg.PayCst.Platform}
*/
private String platform;
/**
* 【必填】
* 订单号
*/
private String orderNo;
/**
* 【必填】
* 金额,单位:分
*/
private Long amount;
/**
* 【必填】
* 订单标题
*/
private String title;
/**
* 【必填】
* 回调地址
*/
private String notifyUrl;
/**
* 【必填】
* appId
*/
private String appId;
/**
* 用户唯一标识
*/
private String openId;
/**
* 【微信必填】
* 商户ID
*/
private String merchantId;
/**
* 【支付宝必填】
* 支付参数
*/
private String payParams;
/**
* 商品描述
*/
private String body;
/**
* 扩展数据
*/
private String extData;
/**
* 设备 ip
*/
private String clientIp;
/**
* 支付条码
* 微信18位纯数字前缀以10、11、12、13、14、15开头
*/
private String barCode;
/**
* 支付宝 授权信息解析,不用传
*/
private AlipayAuthInfoDto alipayAuthInfo;
public void verifyParams() {
AssertUtil.isBlank(platform, "请选择支付方式");
AssertUtil.isBlank(orderNo, "订单号不能为空");
AssertUtil.isBlank(title, "订单标题不能为空");
AssertUtil.isBlank(notifyUrl, "回调地址不能为空");
AssertUtil.isBlank(appId, "appId不能为空");
AssertUtil.isBlank(openId, "用户唯一标识不能为空");
if (PayCst.Platform.WECHAT.equals(platform)) {
AssertUtil.isBlank(merchantId, "商户ID不能为空");
} else if (PayCst.Platform.ALIPAY.equals(platform)) {
AssertUtil.isBlank(payParams, "支付参数不能为空");
alipayAuthInfo = JSONObject.parseObject(payParams, AlipayAuthInfoDto.class);
AssertUtil.isNull(alipayAuthInfo, "支付参数错误");
AssertUtil.isBlank(alipayAuthInfo.getAppAuthToken(), "授权信息错误");
} else {
throw new CzgException("支付平台错误");
}
}
}

View File

@@ -0,0 +1,69 @@
package com.czg.dto.req;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 退款参数
* @author yjjie
* @date 2026/1/14 11:37
*/
@Data
@Accessors(chain = true)
public class RefundParamsDto {
/**
* 【必填】
* 平台
* {@link com.czg.PayCst.Platform}
*/
private String platform;
/**
* 【必填】
* 订单号
*/
private String orderNo;
/**
* 【必填】
* 退款单号
*/
private String refundOrderNo;
/**
* 【必填】
* 退款金额
*/
private Long refundAmount;
/**
* 【必填】
* 订单原金额
*/
private Long orderAmount;
/**
* 【必填】
* 退款原因
*/
private String refundReason;
/**
* 【必填】
* 退款回调地址
*/
private String refundNotifyUrl;
/**
* 【选填】
* 微信商户号
*/
private String merchantId;
/**
* 【选填】
* 支付宝授权信息
*/
private String alipayAuthInfo;
}

View File

@@ -0,0 +1,33 @@
package com.czg.dto.req;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
/**
* @author yjjie
* @date 2025/12/23 21:47
*/
@Data
public class WechatNotifyReqDto {
private String id;
@JSONField(name = "create_time")
private String createTime;
@JSONField(name = "resource_type")
private String resourceType;
@JSONField(name = "event_type")
private String eventType;
private String summary;
private Resource resource;
@Data
public static class Resource {
@JSONField(name = "resource_type")
private String originalType;
private String algorithm;
private String ciphertext;
@JSONField(name = "associated_data")
private String associatedData;
private String nonce;
}
}

View File

@@ -0,0 +1,118 @@
package com.czg.dto.req;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
/**
* @author yjjie
* @date 2025/12/23 22:21
*/
@Data
public class WechatPayNotifyDataDto {
/**
* 公众账号ID
*/
private String appid;
/**
* 商户号
*/
private String mchid;
/**
* 商户订单号
*/
@JSONField(name = "out_trade_no")
private String outTradeNo;
/**
* 微信支付订单号
*/
@JSONField(name = "transaction_id")
private String transactionId;
/**
* 交易类型
* JSAPI公众号支付、小程序支付
* NATIVENative支付
* APPAPP支付
* MICROPAY付款码支付
* MWEBH5支付
* FACEPAY刷脸支付
*/
@JSONField(name = "trade_type")
private String tradeType;
/**
* 交易状态
* SUCCESS—支付成功
* REFUND—转入退款
* NOTPAY—未支付
* CLOSED—已关闭
* REVOKED—已撤销刷卡支付
* USERPAYING--用户支付中
* PAYERROR--支付失败(其他原因,如银行返回失败)
*/
@JSONField(name = "trade_state")
private String tradeState;
/**
* 交易状态描述
*/
@JSONField(name = "trade_state_desc")
private String tradeStateDesc;
/**
* 付款银行
*/
@JSONField(name = "bank_type")
private String bankType;
/**
* 商户数据包
*/
private String attach;
/**
* 支付完成时间
*/
@JSONField(name = "success_time")
private String successTime;
/**
* 金额
*/
private Amount amount;
@Data
public static class Amount {
/**
* 用户支付金额
*/
@JSONField(name = "payer_total")
private Integer payerTotal;
/**
* 货币类型
*/
private String currency;
/**
* 总金额
*/
private Integer total;
}
public boolean isSuccess() {
return "SUCCESS".equals(tradeState);
}
public boolean isClosed() {
return "CLOSED".equals(tradeState);
}
public Long getPayAmount() {
return Long.valueOf(amount.getTotal());
}
}

View File

@@ -55,4 +55,16 @@ public class BankBranchDto {
* 机构全称
*/
private String instName;
/**
* 联行支行边行
*/
@JSONField(name = "bank_branch_id")
private String bankBranchId;
/**
* 联行支行名称
*/
@JSONField(name = "bank_branch_name")
private String bankBranchName;
}

View File

@@ -33,6 +33,11 @@ public class EntryRespDto {
*/
private String alipayOrderId;
/**
* 支付宝授信息
*/
private String alipayAuthInfo;
/**
* 支付宝状态
* {@link com.czg.PayCst.EntryStatus}

View File

@@ -16,6 +16,11 @@ public class EntryThirdRespDto {
*/
private String entryId;
/**
* 支付宝授信息
*/
private String alipayAuthInfo;
/**
* 平台
*/

View File

@@ -0,0 +1,61 @@
package com.czg.dto.resp;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.util.List;
/**
* 微信银行支行列表
* @author yjjie
* @date 2026/1/12 09:32
*/
@Data
public class WechatBankBranchRespDto {
/**
* 开户银行
*/
@JSONField(name = "account_bank")
private String accountBank;
/**
* 开户银行编码
*/
@JSONField(name = "account_bank_code")
private Integer accountBankCode;
/**
* 银行别名
*/
@JSONField(name = "bank_alias")
private String bankAlias;
/**
* 银行别名编码
*/
@JSONField(name = "bank_alias_code")
private String bankAliasCode;
/**
* 银行支行列表
*/
@JSONField(name = "data")
private List<WechatBankBranchList> data;
@Data
public static class WechatBankBranchList {
/**
* 银行支行名称
*/
@JSONField(name = "bank_branch_name")
private String bankBranchName;
/**
* 银行支行编号
*/
@JSONField(name = "bank_branch_id")
private String bankBranchId;
}
}

View File

@@ -347,10 +347,10 @@ public class AlipayEntryManager {
public static void main(String[] args) throws ApiException {
// queryBankBranchList("CMB", "陕西省", "西安市");
queryBankBranchList(null, "CMB", "陕西省", "西安市");
// uploadImage(null, "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240312/31476c871c224389aea0ac4e17c964a3.jpg");
test();
// test();
}
// https://opendocs.alipay.com/solution/0dec7x?pathHash=caec4753 直付通

View File

@@ -9,12 +9,12 @@ import com.czg.dto.req.*;
import com.czg.dto.resp.EntryThirdRespDto;
import com.czg.dto.resp.QueryStatusResp;
import com.czg.exception.CzgException;
import com.czg.pay.AlipayAuthInfoDto;
import com.czg.third.alipay.dto.config.AlipayConfigDto;
import com.czg.utils.UploadFileUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
/**
* 支付宝服务商进件管理
@@ -25,9 +25,10 @@ import java.io.IOException;
@Slf4j
public class AlipayIsvEntryManager {
private static final String ERR_MESSAGE_KEY = "message";
public static QueryStatusResp queryMerchantBatchStatus(AlipayConfigDto configDto, String batchNo) {
if (configDto == null) {
configDto = AlipayConfigDto.getThirdDefaultConfig();
}
QueryStatusResp respDto = new QueryStatusResp()
.setPlatform(PayCst.Platform.ALIPAY);
AlipayClient.setApiClient(configDto);
@@ -87,7 +88,7 @@ public class AlipayIsvEntryManager {
log.error("支付宝查询进件状态异常: {}", body);
JSONObject object = JSONObject.parseObject(body);
respDto.setStatus(PayCst.EntryStatus.REJECTED);
respDto.setFailReason(object.getString(ERR_MESSAGE_KEY));
respDto.setFailReason(object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
return respDto;
}
}
@@ -98,25 +99,31 @@ public class AlipayIsvEntryManager {
* @param reqDto 请求信息
*/
public static EntryThirdRespDto entryMerchant(AlipayConfigDto configDto, AggregateMerchantDto reqDto) {
if (configDto == null) {
configDto = AlipayConfigDto.getThirdDefaultConfig();
}
AlipayClient.setApiClient(configDto);
EntryThirdRespDto respDto = new EntryThirdRespDto()
.setPlatform(PayCst.Platform.ALIPAY);
try {
String batchNo = createRequest(reqDto);
String batchNo = createRequest(configDto, reqDto);
respDto.setEntryId(batchNo);
AlipayOpenAgentFacetofaceSignModel signModel = buildFaceToFaceModel(reqDto, batchNo);
File businessLicensePic = UploadFileUtil.getFileByUrl(reqDto.getBusinessLicenceInfo().getLicensePic().getUrl());
File shopScenePic = UploadFileUtil.getFileByUrl(reqDto.getStoreInfo().getInsidePic().getUrl());
File shopSignBoardPic = UploadFileUtil.getFileByUrl(reqDto.getStoreInfo().getDoorPic().getUrl());
log.info("支付宝开启代商户签约: 请求={}", JSONObject.toJSONString(signModel));
// 构造请求参数以调用接口
AlipayOpenAgentFacetofaceApi api = new AlipayOpenAgentFacetofaceApi();
Object response = api.sign(null, businessLicensePic, signModel, shopScenePic, shopSignBoardPic, null);
log.info("支付宝开启代商户签约: 响应={}", JSONObject.toJSONString(response));
try {
String orderNo = confirmRequest(batchNo);
respDto.setEntryId(orderNo);
String authInfo = confirmRequest(configDto, batchNo);
respDto.setAlipayAuthInfo(authInfo);
respDto.setStatus(PayCst.EntryStatus.INIT);
respDto.setErrorMsg("");
return respDto;
@@ -130,12 +137,12 @@ public class AlipayIsvEntryManager {
log.error("支付宝开启代商户签约,创建应用事务异常: {}", body);
JSONObject object = JSONObject.parseObject(body);
respDto.setStatus(PayCst.EntryStatus.REJECTED);
respDto.setErrorMsg(object.getString(ERR_MESSAGE_KEY));
respDto.setErrorMsg(object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
return respDto;
} catch (IOException e) {
log.error("上传图片出错", e);
} catch (Exception e) {
log.error("支付宝开启代商户签约创建应用事务异常2", e);
respDto.setStatus(PayCst.EntryStatus.REJECTED);
respDto.setErrorMsg("上传图片出错");
respDto.setErrorMsg(e.getMessage());
return respDto;
}
}
@@ -145,7 +152,11 @@ public class AlipayIsvEntryManager {
* @param reqDto 请求信息
* @return 请求ID
*/
public static String createRequest(AggregateMerchantDto reqDto) {
public static String createRequest(AlipayConfigDto configDto, AggregateMerchantDto reqDto) {
if (configDto == null) {
configDto = AlipayConfigDto.getThirdDefaultConfig();
}
AlipayClient.setApiClient(configDto);
AlipayOpenAgentApi api = new AlipayOpenAgentApi();
AlipayOpenAgentCreateModel openModel = new AlipayOpenAgentCreateModel();
@@ -173,27 +184,40 @@ public class AlipayIsvEntryManager {
String body = e.getResponseBody();
log.error("支付宝开启代商户签约,开启事务异常: {}", body);
JSONObject object = JSONObject.parseObject(body);
throw new CzgException("支付宝开启代商户签约,开启事务异常: " + object.getString(ERR_MESSAGE_KEY));
throw new CzgException("支付宝开启代商户签约,开启事务异常: " + object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
}
}
public static String confirmRequest(String batchNo) {
AlipayClient.setApiClient(null);
public static String confirmRequest(AlipayConfigDto configDto, String batchNo) {
if (configDto == null) {
configDto = AlipayConfigDto.getThirdDefaultConfig();
}
AlipayClient.setApiClient(configDto);
// 构造请求参数以调用接口
AlipayOpenAgentCommonsignApi api = new AlipayOpenAgentCommonsignApi();
AlipayOpenAgentCommonsignConfirmModel data = new AlipayOpenAgentCommonsignConfirmModel();
AlipayOpenAgentApi api = new AlipayOpenAgentApi();
AlipayOpenAgentConfirmModel data = new AlipayOpenAgentConfirmModel();
// 设置ISV 代商户操作事务编号
data.setBatchNo(batchNo);
try {
AlipayOpenAgentCommonsignConfirmResponseModel response = api.confirm(data);
AlipayOpenAgentConfirmResponseModel response = api.confirm(data);
log.info("支付宝开启代商户签约,确认事务: 响应={}", response);
return response.getOrderNo();
AlipayAuthInfoDto authInfoDto = new AlipayAuthInfoDto()
.setUserId(response.getUserId())
.setOpenId(response.getOpenId())
.setAuthAppId(response.getAuthAppId())
.setAppAuthToken(response.getAppAuthToken())
.setExpiresIn(response.getExpiresIn())
.setAppRefreshToken(response.getAppRefreshToken())
.setReExpiresIn(response.getReExpiresIn())
.setOrderNo(response.getOrderNo());
return JSONObject.toJSONString(authInfoDto);
} catch (ApiException e) {
String body = e.getResponseBody();
log.error("支付宝开启代商户签约,确认事务异常: {}", body);
JSONObject object = JSONObject.parseObject(body);
throw new CzgException(object.getString(ERR_MESSAGE_KEY));
throw new CzgException(object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
}
}

View File

@@ -0,0 +1,104 @@
package com.czg.third.alipay;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.v3.ApiException;
import com.alipay.v3.api.AlipayTradeApi;
import com.alipay.v3.model.AlipayTradeCreateModel;
import com.alipay.v3.model.AlipayTradeCreateResponseModel;
import com.alipay.v3.model.ExtendParams;
import com.alipay.v3.util.model.CustomizedParams;
import com.czg.PayCst;
import com.czg.dto.req.PayParamsDto;
import com.czg.dto.req.RefundParamsDto;
import com.czg.exception.CzgException;
import com.czg.third.alipay.dto.config.AlipayConfigDto;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* @author yjjie
* @date 2026/1/9 09:30
*/
@Slf4j
public class AlipayIsvPayManager {
/**
* H5支付
*
* @param configDto 配置
* @param paramsDto 参数
*/
public static Map<String, Object> jsapiPay(AlipayConfigDto configDto, PayParamsDto paramsDto) {
try {
AlipayClient.setApiClient(configDto);
AlipayTradeApi api = new AlipayTradeApi();
AlipayTradeCreateModel model = new AlipayTradeCreateModel();
model.setOutTradeNo(paramsDto.getOrderNo());
model.setProductCode("JSAPI_PAY");
model.setOpAppId(paramsDto.getAppId());
model.setOpBuyerOpenId(paramsDto.getOpenId());
model.setTotalAmount(getYuanAmountByFen(paramsDto.getAmount()));
model.setSubject(paramsDto.getTitle());
model.setBody(paramsDto.getBody());
model.setNotifyUrl(paramsDto.getNotifyUrl() + "/" + PayCst.Platform.ALIPAY);
model.setExtendParams(new ExtendParams());
CustomizedParams customizedParams = new CustomizedParams();
customizedParams.setAppAuthToken(paramsDto.getAlipayAuthInfo().getAppAuthToken());
AlipayTradeCreateResponseModel responseModel = api.create(model, customizedParams);
log.info("支付宝 jsapi 支付结果: {}", responseModel);
return new HashMap<>();
} catch (ApiException e) {
String body = e.getResponseBody();
log.error("支付宝 H5 api 支付异常: {}", body);
JSONObject object = JSONObject.parseObject(body);
throw new CzgException(object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
} catch (Exception e) {
log.error("支付宝 H5支付异常: {}", e.getMessage());
throw new CzgException(e.getMessage());
}
}
/**
* 条码支付
*
* @param configDto 配置
* @param paramsDto 参数
*/
public static Map<String, Object> barPay(AlipayConfigDto configDto, PayParamsDto paramsDto) {
try {
AlipayClient.setApiClient(configDto);
return new JSONObject();
// } catch (ApiException e) {
// String body = e.getResponseBody();
// log.error("支付宝 条码支付异常: {}", body);
// JSONObject object = JSONObject.parseObject(body);
// throw new CzgException(object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
} catch (Exception e) {
log.error("支付宝 条码支付异常: {}", e.getMessage());
throw new CzgException(e.getMessage());
}
}
public static Map<String, Object> queryOrder(AlipayConfigDto configDto, String orderNo, String subMerchantId) {
return new HashMap<>();
}
public static Map<String, Object> refundOrder(AlipayConfigDto configDto, RefundParamsDto paramsDto) {
return new HashMap<>();
}
/**
* 金额转换
*/
private static String getYuanAmountByFen(Long amount) {
BigDecimal yuanAmount = new BigDecimal(amount).divide(new BigDecimal(100));
return yuanAmount.toString();
}
}

View File

@@ -32,7 +32,10 @@ public class AlipayConfigDto {
*/
private String domain;
public static AlipayConfigDto getDefaultConfig() {
/**
* 第三方应用 签约当面付
*/
public static AlipayConfigDto getThirdDefaultConfig() {
return new AlipayConfigDto()
.setAppId("2021006121646825")
.setPrivateKey("MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCz3FkdffxZibdwis9W7eOW1dEjGAbSvRDL2ikfeCIW5KZNoIjUqxI0mIoUlLRRKO71QLHZS1Vb2aJp8jeOAqIPa8e76HTneQEzk3FGA8gpraSGvbadHWzvxnmYKsts1TBiEZQL82ySJXhQTJvZ6jyDM7s6wHHUnrH+Qi29QpppQ1sxsoJeCtajUgRg3btD6XbBcyFAX3pzM56Kw9eaIjZoD8WToZOM/Y3sqNL2uo8lLqcIpTrI7Pq5ZOspmBQ+t8v3rS9IdDZZMvd0trzS67AXwHz8rKPBT/lL1A4iHnXCHUvktusX1fPs3/RGY/a7PIddaBLnfY0GcueE16K7QcrXAgMBAAECggEAbSdT2eckp75BWoaTcGEs1tRqeM7TDT/6moyKmnOQ1K3tE31SrSYpBUxxuC3LBNo/sw2RIZtrcTOyMnPyLTgB3DP/4lUf5X51MTTQ8LnI1ypvh+pIki9Sdm3QS33lOOZk149tdpdDk6ozyx/DEcvq74EMpoo2SuAIi5LkKVDrXuehvGA/WeXtpmuPgqRFdIA+JBlA3knHk5XEQY/k2Y31gq5oCwNL9iT9OAZqVkukE6EnvCXE9t2rAV4/snYilaf/UaO+ktgEwSbPBQ8YKlovDAarMBbGtgr6E174A9djlPyR+W/fgx8rlTwSWtieb9MkO8LN3KSxgVs0kY5U8OHg8QKBgQDljJq9kTFHare+W/fAXdUy3tJprfNQCAii6s+GuDfTQiviVQDtWmdtHAN+xU3to7MepvVhwHsqtQnZXKTtZuwwxn82FNl7A5RYD3GVFW+wG6AsGLIdESrWxySoL6Kx8QmNpMEVg8acT/ywzW/RnUXS5vU7GIi8GA0vtyBo24R9KQKBgQDIlf/R9+iNk9oXlbB/k4um9eVvBBS7l5cx4E5Id5Dpp4kGZfPZEa7oDsEUstZZM9mgQLJK/noNWbcf0+BohCR5ux7SC12qIoxwN3k4BzTDqrS8BzFuVVp5PELUsf/uCbRn05iMzpiDUhj3Vde04wvjHYIobfKlZO2HeSWXCpUH/wKBgQC8wSuU6ck90pEY5QMKmZ3wYK1g3PsQOirv3Gmde+nbu7PePsuuYQJfBAQTwCZeXJezgtKP+PjOm2Nn6vhrhpB9YxvD2s0ijET1TG23i5L1myHQYNZFdJJnXgXUjqcX7v5ODMYA7QTqEBPXRnbGRK7fx66rU3dMQ/LD46+wyaFeUQKBgA4QTk53dkuu6SSsLyLSwoDjTsHY5Gc+urAZjQORtoxbXcUgEtfOYJgOqMT9wP+iHgkZYCbX7tDO0IMfxOUvFqueTgvmFhwergAUM6CVCMMLTf689l9JBr3nVrw4+rvC3G5HLLP6rEDQ2cVFtIkPPj8fS4fwJYopKGpOOS9843QbAoGBAMoHH8LqoZ50FLsospx/hJe24Cd8wCgQTXSa/hMqNZ1999JDhftMt7R0ZdB1he2LReACe0K9ntBU4H4u225zZ3wZlyOfoyerAHuLK/ysNlgIIzblZlOxbBJ64Kul8leXzlYy3tOZuZ997KqBcWPCE3LUBBNvM6E3blJUnlmJAVoi")
@@ -47,6 +50,27 @@ public class AlipayConfigDto {
// .setAppId("2021004145625815")
// .setPrivateKey("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCAjDBuS8K/IJb9ui+KuNm/sTUdEiaji4BNpZ92avO1N5JpNlGmac6ec4p3tNFT950sBLcQkClcUpQxUHQzAT6DYNNXOKyvfI/EmcqwCw6PaMNLs/8cV//J2WWZBUhLaOsjKurpm9/3W5MnTh4BGxIfBoeBMA8f8K3BgKdmyKtvIEV2h2cyjsMskdn+g6oNZcmWcms0pvpPHyH46mRaGFhpp0v19wX3WsamGldh1L2VntmaDN3C2XbSrXv90XYp5bEUqwTbLwXpMAlzTibF56d/iqv9oYi8cpAKougUFLOymnbutLNs2tLrEDSFwHcmG2/wbZHybZyYcIgFgv4arf+tAgMBAAECggEAf7hKKlw1y6Z6vvAtalxNZUuRZSfyog3p1bwYWxTavZPQcZ7Zs0lvVDmiO1u5m/7q96BbryY9IhCeUv0H5uF2lhwu/3s9AEL3qTPQkeb6eXxyhhX6A9RfPdM1Qbtg4CQHdHKg4qjP9znSVHwmDZ0y/QaEvdPdQzPjv92u9c2tn4N4x6XyBYcU5gzxiJNnIugCmBgcJo/3H2fgV+XXEhORPvy5of9b4oATHEaLS/8dAS2wuOjhzaGS4MXp3VkXn3XaYjwSzaL03qYWA+xm+aO5sJv8bmqZW7sNVck5o3sPo7cQ4VkBFVzyrRdmJcxcSRJ9MsB9JsrhoKI8pgaXrVie4QKBgQDU2vai0lpBIK/0jzRpPNoqdT8lnafnnWni8nU4kfAh+gCLi+HBPhQRT0kv4unQc2q2/gALE7sgZVO00JGY5a3R0orsojPoUSZlpypGW7GGqKy576NHn0nw4o/PdfysT92VWgt1hlfTf6qfCDhfE9APU+RGvlSWXcT8nxVel3iUaQKBgQCamoJN6+4v+chJvL2nqV8NVVRLp0vDIHxs1QOtKwUodx8Qp1D6CJYtavCXn8aNUFVNQJPJ7TQPpJjXP2rI4SN01weDwx+I+wh8PBGHV6/234R+6TvFgY1PrYgCdfNP4i/E7B4uyEhAxdU73PB8qkqRAeJGok05p7oG71KCOBiYpQKBgEZfGflcuDAeAW5GRhqg3rP4zWa/R7qgZVh9tll8jjp9b96y4XFE99d9MgId8BVVgyt6sEL5Q/2C4ni+F9TH4n6jMADp42VkJuCmsqhOOlP9whU67+2G8Sgtj0QUivPg964f9ffl8XVgGOW5DwIIB9p5btggptCLscufQK5kP545AoGADBvf6tR4wl8w9b2HqTMV08iEIqzGvVC1Dh0c/Zop/EJgN4CzUfIMOSBwGaAVAApzs+pD6QPgGP2OTwWTioo/qa4R05sbxDHNN1XJFa2jhZV6HiqMWOrNs5jm1zJ/zRjtHuJTdtyO9CvKiLbESy9XScY4/8lEfSiK5HIoJzTXkFUCgYAkYkvkW6psJpWj05XWq44UN0n6QOU/Igl35Um/iuOMVhsTmIt09STQVTuzJzfH82+sCqoRsD1blE5unKNUC1DK77aNKTv3Z0dxN9R7FAyfZRiYQXTrbBPBqWjay6FCNxn8e8UsJN4Z6FIV2LGlQI114krSap1MALKLVvnld0NaUQ==")
// .setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiQkrz+emAuS1mB3KKDOMmAZRd/BlPbh7fAIHAqAj1+QCZNcV3o2BTLIIqnuKpSlFXDG3uDzp2VsBxcizXuBbFyPGylnD9CgCj5abyh3+FIHPAZ2IM3TtpqImZ0TSPGXrMli4Nir7MvZktgccCqQKCC4o6iaDGz+UwWwJUIPna8fm2tiTZ+KH150CZbKVj4ZGNpBh5XSV/1dRgyQIV9D/EwSbkZ0n6VgKQLJBi0C2UE3QB17aL1Ir6+gDXIDbknN8O7GUD3aMGdThYdSRUb5wp9CZ5qfV7vCS/CgaRo38nhH3NOzkTL+7v0m1ZDHPmqEkn9VzZN6sCQdL7PoAOjHOCwIDAQAB")
// .setDomain("https://openapi.alipay.com/gateway.do");
}
/**
* 直付通商户配置
*/
public static AlipayConfigDto getDefaultConfig() {
// return new AlipayConfigDto()
// .setAppId("2021006121646825")
// .setPrivateKey("MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCz3FkdffxZibdwis9W7eOW1dEjGAbSvRDL2ikfeCIW5KZNoIjUqxI0mIoUlLRRKO71QLHZS1Vb2aJp8jeOAqIPa8e76HTneQEzk3FGA8gpraSGvbadHWzvxnmYKsts1TBiEZQL82ySJXhQTJvZ6jyDM7s6wHHUnrH+Qi29QpppQ1sxsoJeCtajUgRg3btD6XbBcyFAX3pzM56Kw9eaIjZoD8WToZOM/Y3sqNL2uo8lLqcIpTrI7Pq5ZOspmBQ+t8v3rS9IdDZZMvd0trzS67AXwHz8rKPBT/lL1A4iHnXCHUvktusX1fPs3/RGY/a7PIddaBLnfY0GcueE16K7QcrXAgMBAAECggEAbSdT2eckp75BWoaTcGEs1tRqeM7TDT/6moyKmnOQ1K3tE31SrSYpBUxxuC3LBNo/sw2RIZtrcTOyMnPyLTgB3DP/4lUf5X51MTTQ8LnI1ypvh+pIki9Sdm3QS33lOOZk149tdpdDk6ozyx/DEcvq74EMpoo2SuAIi5LkKVDrXuehvGA/WeXtpmuPgqRFdIA+JBlA3knHk5XEQY/k2Y31gq5oCwNL9iT9OAZqVkukE6EnvCXE9t2rAV4/snYilaf/UaO+ktgEwSbPBQ8YKlovDAarMBbGtgr6E174A9djlPyR+W/fgx8rlTwSWtieb9MkO8LN3KSxgVs0kY5U8OHg8QKBgQDljJq9kTFHare+W/fAXdUy3tJprfNQCAii6s+GuDfTQiviVQDtWmdtHAN+xU3to7MepvVhwHsqtQnZXKTtZuwwxn82FNl7A5RYD3GVFW+wG6AsGLIdESrWxySoL6Kx8QmNpMEVg8acT/ywzW/RnUXS5vU7GIi8GA0vtyBo24R9KQKBgQDIlf/R9+iNk9oXlbB/k4um9eVvBBS7l5cx4E5Id5Dpp4kGZfPZEa7oDsEUstZZM9mgQLJK/noNWbcf0+BohCR5ux7SC12qIoxwN3k4BzTDqrS8BzFuVVp5PELUsf/uCbRn05iMzpiDUhj3Vde04wvjHYIobfKlZO2HeSWXCpUH/wKBgQC8wSuU6ck90pEY5QMKmZ3wYK1g3PsQOirv3Gmde+nbu7PePsuuYQJfBAQTwCZeXJezgtKP+PjOm2Nn6vhrhpB9YxvD2s0ijET1TG23i5L1myHQYNZFdJJnXgXUjqcX7v5ODMYA7QTqEBPXRnbGRK7fx66rU3dMQ/LD46+wyaFeUQKBgA4QTk53dkuu6SSsLyLSwoDjTsHY5Gc+urAZjQORtoxbXcUgEtfOYJgOqMT9wP+iHgkZYCbX7tDO0IMfxOUvFqueTgvmFhwergAUM6CVCMMLTf689l9JBr3nVrw4+rvC3G5HLLP6rEDQ2cVFtIkPPj8fS4fwJYopKGpOOS9843QbAoGBAMoHH8LqoZ50FLsospx/hJe24Cd8wCgQTXSa/hMqNZ1999JDhftMt7R0ZdB1he2LReACe0K9ntBU4H4u225zZ3wZlyOfoyerAHuLK/ysNlgIIzblZlOxbBJ64Kul8leXzlYy3tOZuZ997KqBcWPCE3LUBBNvM6E3blJUnlmJAVoi")
// .setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiQkrz+emAuS1mB3KKDOMmAZRd/BlPbh7fAIHAqAj1+QCZNcV3o2BTLIIqnuKpSlFXDG3uDzp2VsBxcizXuBbFyPGylnD9CgCj5abyh3+FIHPAZ2IM3TtpqImZ0TSPGXrMli4Nir7MvZktgccCqQKCC4o6iaDGz+UwWwJUIPna8fm2tiTZ+KH150CZbKVj4ZGNpBh5XSV/1dRgyQIV9D/EwSbkZ0n6VgKQLJBi0C2UE3QB17aL1Ir6+gDXIDbknN8O7GUD3aMGdThYdSRUb5wp9CZ5qfV7vCS/CgaRo38nhH3NOzkTL+7v0m1ZDHPmqEkn9VzZN6sCQdL7PoAOjHOCwIDAQAB")
// .setDomain("https://openapi.alipay.com");
return new AlipayConfigDto()
.setAppId("2021004174605036")
.setPrivateKey("MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD48HaUoV7OH7os+9L01kHgxzwIhJick4OkFq4aHsntsXEJ J3gedhuEZtV8oHKZ30DPW12IJ4S8NXtpr8OWaqrAPFonf4wVaRY1d0yIAea57kfLEn9oOEEy4FzARgMNDkyxC+/3OUdGbLHpTjfVX3gusXsEhUDy1/WewihAkoNYF37+W3W/uVLzeWoPq0EcUbRv/G/t/p6gL69ltsMAiVFG4Q/Yk24YAN6lYgBPNLXUEwQ1Q+T+1omjfavHgvarKOp33z3JOUH+aGOmDsJ5Y9gyGtJzOCipAd8Zcv+T1ygsEzZYO1/gzcbPnfO1ShqStCHzssuw8FBVx2JdfQKXKMMNAgMBAAECggEAVTrO/pg5Q00titU1Jspsh67u6OOs9H605Ws2dI7yB8VmtAGlaJh7V1t14FN2qSP8poHbhhAxq9aLyGV7C3a9u09udnN+3J28EtYjh7VO732bavWMVXxdJjQWzWWrCb9JlpxFrlkYBA6W4w/6ob0sAqCVQ7jzwbEa0R4cde8ztOa5nysKSfr4YTSs0gqvoiC6fmg8eiRJraEQBoYz9VkKFtOhhh/4w5FhVcYQ2gQvZ3kK3QVuD1eJIQKlCtz8qaox9lXKDiZT4SCmnKshdUL0u5TYIcYeBjZmhJz0Q50KHcpZrCs5y7I0+vRBH3hU+TKSQt7ureymwhbwWMHScLV2gQKBgQD+58SHXhr5M8NGagAmTdsgmCnNv2kOYMd4STyPMY10SVwCv1Bk808ZuP+7e558J1b5/OuDLI5dLq6xrZ/1wLv1G++XqxI00hlFuWS5mUGJVcXotT1mw20rVeUILc7Qe3mLvbMGgfyKf4A7Qa5SSZ4bDeDTJYaFxyiQ281hMzDuPQKBgQD6AiL/Na2/uPH4CG6juwpjYvYVUcjK+7gbRwf3wWsWMpk90Z4ju2iUiP5c1J/oK9P+1T3PIr6M4Xjza8JJj+r9KC/PVB0gBv6vVM96cDpKUEy/UMpcn/T81vqj/Z+WEOODU8Ms6NiTTm+u9ldvpCjbu0u8M+9c0JeIyadJvSTFEQKBgQCsxmFyM3nq8YfpgU2qqNjfBeRH3faSVUy+nj1a/YZYjKS+A/i1BCnYUImeBVNN6chNV342ggvY4xxruDiU9Vcw8wd58O09Oi8BEIFSP6upL6cebUI6Fjo3xlegLJRiwV6INkNTJOYM5hD/mSxUACwXQFfkJipBINXBIgraWD1RLQKBgQCj49axWq0F6+WjZVOyPaD3uh37p9trRUxRhWTxw3fB23WdktaKMgbCqHOmwzP4bRLSEVQtf2dOz1gMqu14b8HqJvgAf/F/11YJ9hz09LEhmjZVjE68HZfqT7uK2W5OX8/lfXmK7TFcj6SjG5YB96lZMhTZ0WnufEd6QkdKDZYXIQKBgQD9GDTcIMbFwbEaKHnfZaTD3f876EGRgsgrCxwdEk7LBCRPwWo7yI929M4psIlpNwNeiyjBkBunWIVkpznp6qPtJqagIPUYesU4f5v6/okq5wcpaNKSkWbIvWVLaLGOiA1aeGJtbpMpyClbSr52puHpRRdvAiIEQ74yYh0JX8q96g==")
.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiQkrz+emAuS1mB3KKDOMmAZRd/BlPbh7fAIHAqAj1+QCZNcV3o2BTLIIqnuKpSlFXDG3uDzp2VsBxcizXuBbFyPGylnD9CgCj5abyh3+FIHPAZ2IM3TtpqImZ0TSPGXrMli4Nir7MvZktgccCqQKCC4o6iaDGz+UwWwJUIPna8fm2tiTZ+KH150CZbKVj4ZGNpBh5XSV/1dRgyQIV9D/EwSbkZ0n6VgKQLJBi0C2UE3QB17aL1Ir6+gDXIDbknN8O7GUD3aMGdThYdSRUb5wp9CZ5qfV7vCS/CgaRo38nhH3NOzkTL+7v0m1ZDHPmqEkn9VzZN6sCQdL7PoAOjHOCwIDAQAB")
.setDomain("https://openapi.alipay.com/gateway.do");
// return new AlipayConfigDto()
// .setAppId("2021004145625815")
// .setPrivateKey("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCAjDBuS8K/IJb9ui+KuNm/sTUdEiaji4BNpZ92avO1N5JpNlGmac6ec4p3tNFT950sBLcQkClcUpQxUHQzAT6DYNNXOKyvfI/EmcqwCw6PaMNLs/8cV//J2WWZBUhLaOsjKurpm9/3W5MnTh4BGxIfBoeBMA8f8K3BgKdmyKtvIEV2h2cyjsMskdn+g6oNZcmWcms0pvpPHyH46mRaGFhpp0v19wX3WsamGldh1L2VntmaDN3C2XbSrXv90XYp5bEUqwTbLwXpMAlzTibF56d/iqv9oYi8cpAKougUFLOymnbutLNs2tLrEDSFwHcmG2/wbZHybZyYcIgFgv4arf+tAgMBAAECggEAf7hKKlw1y6Z6vvAtalxNZUuRZSfyog3p1bwYWxTavZPQcZ7Zs0lvVDmiO1u5m/7q96BbryY9IhCeUv0H5uF2lhwu/3s9AEL3qTPQkeb6eXxyhhX6A9RfPdM1Qbtg4CQHdHKg4qjP9znSVHwmDZ0y/QaEvdPdQzPjv92u9c2tn4N4x6XyBYcU5gzxiJNnIugCmBgcJo/3H2fgV+XXEhORPvy5of9b4oATHEaLS/8dAS2wuOjhzaGS4MXp3VkXn3XaYjwSzaL03qYWA+xm+aO5sJv8bmqZW7sNVck5o3sPo7cQ4VkBFVzyrRdmJcxcSRJ9MsB9JsrhoKI8pgaXrVie4QKBgQDU2vai0lpBIK/0jzRpPNoqdT8lnafnnWni8nU4kfAh+gCLi+HBPhQRT0kv4unQc2q2/gALE7sgZVO00JGY5a3R0orsojPoUSZlpypGW7GGqKy576NHn0nw4o/PdfysT92VWgt1hlfTf6qfCDhfE9APU+RGvlSWXcT8nxVel3iUaQKBgQCamoJN6+4v+chJvL2nqV8NVVRLp0vDIHxs1QOtKwUodx8Qp1D6CJYtavCXn8aNUFVNQJPJ7TQPpJjXP2rI4SN01weDwx+I+wh8PBGHV6/234R+6TvFgY1PrYgCdfNP4i/E7B4uyEhAxdU73PB8qkqRAeJGok05p7oG71KCOBiYpQKBgEZfGflcuDAeAW5GRhqg3rP4zWa/R7qgZVh9tll8jjp9b96y4XFE99d9MgId8BVVgyt6sEL5Q/2C4ni+F9TH4n6jMADp42VkJuCmsqhOOlP9whU67+2G8Sgtj0QUivPg964f9ffl8XVgGOW5DwIIB9p5btggptCLscufQK5kP545AoGADBvf6tR4wl8w9b2HqTMV08iEIqzGvVC1Dh0c/Zop/EJgN4CzUfIMOSBwGaAVAApzs+pD6QPgGP2OTwWTioo/qa4R05sbxDHNN1XJFa2jhZV6HiqMWOrNs5jm1zJ/zRjtHuJTdtyO9CvKiLbESy9XScY4/8lEfSiK5HIoJzTXkFUCgYAkYkvkW6psJpWj05XWq44UN0n6QOU/Igl35Um/iuOMVhsTmIt09STQVTuzJzfH82+sCqoRsD1blE5unKNUC1DK77aNKTv3Z0dxN9R7FAyfZRiYQXTrbBPBqWjay6FCNxn8e8UsJN4Z6FIV2LGlQI114krSap1MALKLVvnld0NaUQ==")
// .setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiQkrz+emAuS1mB3KKDOMmAZRd/BlPbh7fAIHAqAj1+QCZNcV3o2BTLIIqnuKpSlFXDG3uDzp2VsBxcizXuBbFyPGylnD9CgCj5abyh3+FIHPAZ2IM3TtpqImZ0TSPGXrMli4Nir7MvZktgccCqQKCC4o6iaDGz+UwWwJUIPna8fm2tiTZ+KH150CZbKVj4ZGNpBh5XSV/1dRgyQIV9D/EwSbkZ0n6VgKQLJBi0C2UE3QB17aL1Ir6+gDXIDbknN8O7GUD3aMGdThYdSRUb5wp9CZ5qfV7vCS/CgaRo38nhH3NOzkTL+7v0m1ZDHPmqEkn9VzZN6sCQdL7PoAOjHOCwIDAQAB")
// .setDomain("https://openapi.alipay.com/gateway.do");
}
}

View File

@@ -0,0 +1,60 @@
package com.czg.third.wechat;
import javax.crypto.AEADBadTagException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* 微信参数 AES 解密
* @author GYJoker
*/
public class WechatAesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public WechatAesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key长度必须为32个字节");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
throws GeneralSecurityException {
try {
// 调试信息:打印参数信息
System.out.println("associatedData长度: " + (associatedData != null ? associatedData.length : 0));
System.out.println("nonce长度: " + (nonce != null ? nonce.length : 0));
System.out.println("ciphertext长度: " + ciphertext.length());
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
// 处理 associatedData确保使用空数组而非 null
cipher.updateAAD(associatedData != null ? associatedData : new byte[0]);
byte[] decodedCiphertext = Base64.getDecoder().decode(ciphertext);
System.out.println("解码后密文长度: " + decodedCiphertext.length);
byte[] plaintext = cipher.doFinal(decodedCiphertext);
return new String(plaintext, StandardCharsets.UTF_8);
} catch (AEADBadTagException e) {
// 捕获标签不匹配异常,提供更详细的错误信息
throw new GeneralSecurityException("解密失败: 标签不匹配,可能是密钥错误、数据被篡改或参数不匹配", e);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException("无效的密钥或参数", e);
}
}
}

View File

@@ -1,11 +1,14 @@
package com.czg.third.wechat;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.PayCst;
import com.czg.dto.req.*;
import com.czg.dto.resp.EntryThirdRespDto;
import com.czg.dto.resp.QueryStatusResp;
import com.czg.dto.resp.WechatBankBranchRespDto;
import com.czg.exception.CzgException;
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
import com.czg.third.wechat.dto.req.entry.*;
@@ -15,11 +18,13 @@ import com.czg.third.wechat.dto.req.entry.business.WechatEntryLicenseReqDto;
import com.czg.third.wechat.dto.req.entry.business.sales.WechatEntryMiniProgramReqDto;
import com.czg.third.wechat.dto.req.entry.business.sales.WechatEntrySalesInfoReqDto;
import com.czg.third.wechat.dto.req.entry.business.sales.WechatEntryStoreInfoReqDto;
import com.czg.third.wechat.dto.req.entry.id.WechatEntryIdCardReqDto;
import com.czg.third.wechat.dto.resp.WechatAuditDetail;
import com.czg.third.wechat.dto.resp.WechatQueryStateResp;
import com.czg.utils.UploadFileUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.PrivacyEncryptor;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.service.file.FileUploadService;
import com.wechat.pay.java.service.file.model.FileUploadResponse;
import lombok.extern.slf4j.Slf4j;
@@ -52,15 +57,14 @@ public class WechatEntryManager {
String resp = WechatReqUtils.getReq(configDto, "/v3/applyment4sub/applyment/applyment_id/" + applyId, Map.of());
JSONObject object = JSONObject.parseObject(resp);
JSONObject data = object.getJSONObject("data");
if (data == null) {
if (resp.contains("message")) {
log.error("微信查询进件状态失败:{}", resp);
queryStatusResp.setFailReason(object.getString("message"));
queryStatusResp.setStatus(PayCst.EntryStatus.REJECTED);
return queryStatusResp;
}
log.info("微信查询进件状态:{}", resp);
WechatQueryStateResp stateResp = JSONObject.parseObject(data.toJSONString(), WechatQueryStateResp.class);
WechatQueryStateResp stateResp = JSONObject.parseObject(resp, WechatQueryStateResp.class);
queryStatusResp.setApplyId(stateResp.getApplyId());
switch (stateResp.getApplyState()) {
@@ -71,6 +75,10 @@ public class WechatEntryManager {
case "APPLYMENT_STATE_AUDITING" -> {
queryStatusResp.setStatus(PayCst.EntryStatus.AUDIT);
queryStatusResp.setFailReason("");
queryStatusResp.setSignUrl(stateResp.getSignUrl());
if (StrUtil.isNotBlank(queryStatusResp.getSignUrl())) {
queryStatusResp.setStatus(PayCst.EntryStatus.SIGN);
}
}
case "APPLYMENT_STATE_REJECTED" -> {
queryStatusResp.setStatus(PayCst.EntryStatus.REJECTED);
@@ -102,20 +110,19 @@ public class WechatEntryManager {
* @param reqDto 请求信息
*/
public static EntryThirdRespDto entryMerchant(WechatPayConfigDto configDto, AggregateMerchantDto reqDto) {
WechatEntryReqDto entryReqDto = buildEntryParams(configDto, reqDto);
EntryThirdRespDto respDto = new EntryThirdRespDto()
.setPlatform(PayCst.Platform.WECHAT);
log.info("微信进件参数:{}", JSONObject.toJSONString(entryReqDto));
try {
WechatEntryReqDto entryReqDto = buildEntryParams(configDto, reqDto);
log.info("微信进件参数:{}", JSONObject.toJSONString(entryReqDto));
String params = JSONObject.toJSONString(entryReqDto, JSONWriter.Feature.IgnoreEmpty);
String respBody = WechatReqUtils.postReq(configDto, "/v3/applyment4sub/applyment/", params);
JSONObject object = JSONObject.parseObject(respBody);
JSONObject data = object.getJSONObject("data");
log.info("微信进件结果:{}", respBody);
if (data != null) {
if (respBody.contains("applyment_id")) {
respDto.setStatus(PayCst.EntryStatus.INIT);
respDto.setEntryId(data.getString("applyment_id"));
respDto.setEntryId(object.getString("applyment_id"));
respDto.setErrorMsg("");
} else {
respDto.setStatus(PayCst.EntryStatus.REJECTED);
@@ -123,7 +130,7 @@ public class WechatEntryManager {
respDto.setErrorMsg(object.getString("message"));
}
} catch (Exception e) {
log.error("微信进件报错:{}", e.getMessage(), e);
log.error("微信进件报错:{}", e.getMessage());
respDto.setStatus(PayCst.EntryStatus.REJECTED);
respDto.setEntryId("");
respDto.setErrorMsg(e.getMessage());
@@ -138,10 +145,10 @@ public class WechatEntryManager {
return JSONObject.parseObject(resp);
}
public static JSONObject queryBankBranchList(WechatPayConfigDto configDto, String bankAliceCode, String cityCode, Integer offset, Integer limit) {
public static WechatBankBranchRespDto queryBankBranchList(WechatPayConfigDto configDto, String bankAliceCode, String cityCode, Integer offset, Integer limit) {
String resp = WechatReqUtils.getReq(configDto, "/v3/capital/capitallhh/banks/" + bankAliceCode + "/branches", Map.of("city_code", cityCode, "offset", offset, "limit", limit));
log.info("微信查询银行支行列表:{}", resp);
return JSONObject.parseObject(resp);
return JSONObject.parseObject(resp, WechatBankBranchRespDto.class);
}
public static JSONObject queryProvinceList(WechatPayConfigDto configDto) {
@@ -202,8 +209,10 @@ public class WechatEntryManager {
);
return uploadResponse.getMediaId();
} catch (MalformedMessageException e) {
log.error("微信上传图片报错1URL{}", url);
} catch (Exception e) {
log.error("微信上传图片报错URL{},错误信息:{}", url, e.getMessage(), e);
log.error("微信上传图片报错2URL{}", url);
}
return "";
}
@@ -238,7 +247,7 @@ public class WechatEntryManager {
contactInfo.setContactIdDocCopy(baseInfo.getContactIdCardFrontPic().getWechatId());
contactInfo.setContactIdDocCopyBack(baseInfo.getContactIdCardBackPic().getWechatId());
contactInfo.setContactPeriodBegin(baseInfo.getContactPersonIdStartDate());
contactInfo.setContactPeriodEnd(baseInfo.getContactPersonIdEndDate());
contactInfo.setContactPeriodEnd(PayCst.LONG_TERM_DATE.equals(baseInfo.getContactPersonIdEndDate()) ? "长期" : baseInfo.getContactPersonIdEndDate());
contactInfo.setMobilePhone(encryptor.encrypt(baseInfo.getContactPhone()));
contactInfo.setContactEmail(encryptor.encrypt(baseInfo.getContactEmail()));
} else if (PayCst.ContactPersonType.LEGAL.equals(baseInfo.getContactPersonType())) {
@@ -247,7 +256,7 @@ public class WechatEntryManager {
contactInfo.setContactIdDocCopy(legalPersonInfo.getIdCardFrontPic().getWechatId());
contactInfo.setContactIdDocCopyBack(legalPersonInfo.getIdCardBackPic().getWechatId());
contactInfo.setContactPeriodBegin(legalPersonInfo.getLegalIdPersonStartDate());
contactInfo.setContactPeriodEnd(legalPersonInfo.getLegalPersonIdEndDate());
contactInfo.setContactPeriodEnd(PayCst.LONG_TERM_DATE.equals(legalPersonInfo.getLegalPersonIdEndDate()) ? "长期" : legalPersonInfo.getLegalPersonIdEndDate());
contactInfo.setMobilePhone(encryptor.encrypt(legalPersonInfo.getLegalPersonPhone()));
contactInfo.setContactEmail(encryptor.encrypt(legalPersonInfo.getLegalPersonEmail()));
} else {
@@ -278,10 +287,20 @@ public class WechatEntryManager {
licenseReqDto.setLegalPerson(legalPersonInfo.getLegalPersonName());
licenseReqDto.setLicenseAddress(businessLicenceInfo.getRegisteredAddress());
licenseReqDto.setPeriodBegin(businessLicenceInfo.getLicenceStartDate());
licenseReqDto.setPeriodEnd(businessLicenceInfo.getLicenceEndDate());
licenseReqDto.setPeriodEnd(PayCst.LONG_TERM_DATE.equals(businessLicenceInfo.getLicenceEndDate()) ? "长期" : businessLicenceInfo.getLicenceEndDate());
subjectInfo.setBusinessLicenseInfo(licenseReqDto);
WechatEntryIdentityReqDto identityInfo = new WechatEntryIdentityReqDto();
identityInfo.setIdHolderType(PayCst.ContactPersonType.LEGAL);
identityInfo.setIdDocType("IDENTIFICATION_TYPE_IDCARD");
WechatEntryIdCardReqDto idCardInfo = new WechatEntryIdCardReqDto();
idCardInfo.setIdCardCopy(legalPersonInfo.getIdCardFrontPic().getWechatId());
idCardInfo.setIdCardNational(legalPersonInfo.getIdCardFrontPic().getWechatId());
idCardInfo.setIdCardName(encryptor.encrypt(legalPersonInfo.getLegalPersonName()));
idCardInfo.setIdCardNumber(encryptor.encrypt(legalPersonInfo.getLegalPersonId()));
idCardInfo.setIdCardAddress(encryptor.encrypt(legalPersonInfo.getLegalAddress()));
idCardInfo.setCardPeriodBegin(legalPersonInfo.getLegalIdPersonStartDate());
idCardInfo.setCardPeriodEnd(legalPersonInfo.getLegalPersonIdEndDate());
identityInfo.setIdCardInfo(idCardInfo);
subjectInfo.setIdentityInfo(identityInfo);
entryParams.setSubjectInfo(subjectInfo);
@@ -294,8 +313,8 @@ public class WechatEntryManager {
bizStoreInfo.setBizStoreName(baseInfo.getShortName());
bizStoreInfo.setBizAddressCode(storeInfo.getMercAreaCode());
bizStoreInfo.setBizStoreAddress(storeInfo.getBusinessAddress());
bizStoreInfo.setStoreEntrancePic(List.of(storeInfo.getDoorPic().getWechatId()));
bizStoreInfo.setIndoorPic(List.of(storeInfo.getInsidePic().getWechatId(), storeInfo.getCashierDeskPic().getWechatId()));
bizStoreInfo.setStoreEntrancePic(storeInfo.getDoorPic().getWechatId());
bizStoreInfo.setIndoorPic(storeInfo.getInsidePic().getWechatId());
salesInfo.setBizStoreInfo(bizStoreInfo);
WechatEntryMiniProgramReqDto miniProgramInfo = new WechatEntryMiniProgramReqDto();
miniProgramInfo.setMiniProgramAppid("wxd88fffa983758a30");
@@ -313,6 +332,7 @@ public class WechatEntryManager {
WechatEntryBankAccountReqDto bankAccountReqInfo = new WechatEntryBankAccountReqDto();
bankAccountReqInfo.setBankAccountType("21".equals(settlementInfo.getSettlementCardType()) ? "BANK_ACCOUNT_TYPE_CORPORATE" : "BANK_ACCOUNT_TYPE_PERSONAL");
bankAccountReqInfo.setAccountName(encryptor.encrypt(settlementInfo.getSettlementName()));
bankAccountReqInfo.setBankAddressCode(settlementInfo.getOpenAccCityId());
bankAccountReqInfo.setAccountBank(settlementInfo.getBankName());
bankAccountReqInfo.setBankBranchId(settlementInfo.getBankBranchCode());
bankAccountReqInfo.setBankName(settlementInfo.getBankBranchName());
@@ -325,14 +345,19 @@ public class WechatEntryManager {
public static void main(String[] args) throws IOException {
queryMerchantEntryStatus(null, "20220106000000000001");
// queryMerchantEntryStatus(null, "20220106000000000001");
// int offset = 0;
// Integer limit = 100;
int offset = 0;
Integer limit = 100;
// JSONObject resp = queryBankList(null, offset, limit);
// queryBankBranchList(dto, "1000009561", "110000", offset, limit);
// queryBankBranchList(dto, "1000009561", "29", offset, limit);
// queryProvinceList(null);
// queryCityList(null, "28");
// queryBankBranchList(null, "1000009547", "931", offset, limit);
// queryBankBranchList(null, "1000009561", "29", offset, limit);
queryBankBranchList(null, "1000005241", "29", offset, limit);
// uploadImage(null, "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/5/ec5bafd00f96466fb3efe545a058f08b.png");
// queryProvinceList(dto);
// queryCityList(dto, "28");

View File

@@ -1,11 +1,380 @@
package com.czg.third.wechat;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.PayCst;
import com.czg.dto.req.PayParamsDto;
import com.czg.dto.req.RefundParamsDto;
import com.czg.exception.CzgException;
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.core.util.NonceUtil;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
* @author yjjie
* @date 2025/12/26 09:15
*/
@Slf4j
public class WechatPayManager {
private static final String PAY_SUCCESS = "SUCCESS";
private static final String BAR_PAY_URL = "https://api.mch.weixin.qq.com/pay/micropay";
/**
* jsapi 小程序支付
*
* @param configDto 配置
* @param paramsDto 参数
*/
public static Map<String, Object> jsapiPay(WechatPayConfigDto configDto, PayParamsDto paramsDto) {
if (configDto == null) {
configDto = WechatPayConfigDto.getDefaultConfig();
}
try {
JSONObject reqData = new JSONObject();
reqData.put("sp_appid", paramsDto.getAppId());
reqData.put("sp_mchid", configDto.getMerchantId());
reqData.put("sub_mchid", paramsDto.getMerchantId());
reqData.put("description", paramsDto.getTitle());
reqData.put("out_trade_no", paramsDto.getOrderNo());
reqData.put("notify_url", paramsDto.getNotifyUrl() + "/" + PayCst.Platform.WECHAT);
reqData.put("attach", paramsDto.getExtData());
JSONObject amount = new JSONObject();
amount.put("total", paramsDto.getAmount());
reqData.put("amount", amount);
JSONObject payer = new JSONObject();
payer.put("sp_openid", paramsDto.getOpenId());
reqData.put("payer", payer);
String string = WechatReqUtils.postReq(configDto, "/v3/pay/partner/transactions/jsapi", reqData.toJSONString());
log.info("微信支付请求结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), string);
JSONObject object = JSONObject.parseObject(string);
long timestamp = Instant.now().getEpochSecond();
String nonceStr = NonceUtil.createNonce(32);
String packageVal = "prepay_id=" + object.getString("prepay_id");
String message =
paramsDto.getAppId() + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
Config config = WechatConfig.getRsaConfig(configDto);
Signer signer = config.createSigner();
String sign = signer.sign(message).getSign();
JSONObject res = new JSONObject();
res.put("appId", paramsDto.getAppId());
res.put("timeStamp", String.valueOf(timestamp));
res.put("nonceStr", nonceStr);
res.put("package", packageVal);
res.put("signType", "RSA");
res.put("paySign", sign);
log.info("微信支付签名结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), res);
return res;
} catch (Exception e) {
log.error("微信支付异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage());
throw new CzgException("微信支付异常");
}
}
/**
* 条码支付
* 用户付款码规则18位纯数字前缀以10、11、12、13、14、15开头
*
* @param configDto 配置
* @param paramsDto 参数
*/
public static Map<String, Object> barPay(WechatPayConfigDto configDto, PayParamsDto paramsDto) {
try {
if (configDto == null) {
configDto = WechatPayConfigDto.getDefaultConfig();
}
String nonceStr = NonceUtil.createNonce(32);
Map<String, Object> payMap = new HashMap<>();
Document document = DocumentHelper.createDocument();
// 添加根元素
Element xml = document.addElement("xml");
addElementIfNotEmpty(xml, "appid", paramsDto.getAppId());
payMap.put("appid", paramsDto.getAppId());
addElementIfNotEmpty(xml, "mch_id", configDto.getMerchantId());
payMap.put("mch_id", configDto.getMerchantId());
addElementIfNotEmpty(xml, "sub_mch_id", paramsDto.getMerchantId());
payMap.put("sub_mch_id", paramsDto.getMerchantId());
addElementIfNotEmpty(xml, "nonce_str", nonceStr);
payMap.put("nonce_str", nonceStr);
addElementIfNotEmpty(xml, "body", paramsDto.getTitle());
payMap.put("body", paramsDto.getTitle());
addElementIfNotEmpty(xml, "out_trade_no", paramsDto.getOrderNo());
payMap.put("out_trade_no", paramsDto.getOrderNo());
addElementIfNotEmpty(xml, "total_fee", paramsDto.getAmount());
payMap.put("total_fee", paramsDto.getAmount());
addElementIfNotEmpty(xml, "spbill_create_ip", paramsDto.getClientIp());
payMap.put("spbill_create_ip", paramsDto.getClientIp());
addElementIfNotEmpty(xml, "auth_code", paramsDto.getBarCode());
payMap.put("auth_code", paramsDto.getBarCode());
if (StrUtil.isNotBlank(paramsDto.getExtData())) {
addElementIfNotEmpty(xml, "attach", paramsDto.getExtData());
payMap.put("attach", paramsDto.getExtData());
}
String sign = signBarPayParam(configDto, payMap);
addElementIfNotEmpty(xml, "sign", sign);
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(System.out, format);
writer.write(document);
String xmlStr = document.asXML();
log.info("微信条码支付参数:{}", xmlStr);
String post = HttpUtil.post(BAR_PAY_URL, xmlStr);
log.info("微信条码支付请求结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), post);
JSONObject res = new JSONObject();
res.put("orderNo", paramsDto.getOrderNo());
SAXReader saxReader = new SAXReader();
Document read = saxReader.read(stringToInputStream(post));
Element rootElement = read.getRootElement();
String returnCode = rootElement.elementText("return_code");
String errCode = rootElement.elementText("err_code");
String errCodeDes = rootElement.elementText("err_code_des");
res.put("message", errCodeDes);
if (StrUtil.isNotBlank(errCode)) {
if ("SYSTEMERROR".equals(errCode) || "BANKERROR".equals(errCode) || "USERPAYING".equals(errCode)) {
// 等待结果
log.info("微信条码支付等待结果: orderNo = {}, err {}", paramsDto.getOrderNo(), errCodeDes);
res.put("status", "TRADE_AWAIT");
return res;
}
res.put("status", "TRADE_FAIL");
return res;
}
if (!PAY_SUCCESS.equals(returnCode)) {
log.error("微信条码支付失败: orderNo = {}, msg = {}", paramsDto.getOrderNo(), rootElement.elementText("return_msg"));
res.put("status", "TRADE_FAIL");
return res;
}
// 支付成功
log.info("微信条码支付成功: orderNo = {}, msg = {}", paramsDto.getOrderNo(), rootElement.elementText("return_msg"));
res.put("status", "TRADE_SUCCESS");
return res;
} catch (CzgException e) {
throw e;
} catch (Exception e) {
log.error("微信条码支付异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage());
throw new CzgException("微信支付异常");
}
}
/**
* 查询订单
*
* @param configDto 配置
* @param orderNo 订单号
* @param subMerchantId 子商户号
* SUCCESS支付成功
* REFUND转入退款
* NOTPAY未支付
* CLOSED已关闭
* REVOKED已撤销仅付款码支付会返回
* USERPAYING用户支付中仅付款码支付会返回
* PAYERROR支付失败仅付款码支付会返回
*/
public static Map<String, Object> queryOrder(WechatPayConfigDto configDto, String orderNo, String subMerchantId) {
try {
if (configDto == null) {
configDto = WechatPayConfigDto.getDefaultConfig();
}
String resp = WechatReqUtils.getReq(configDto, "/v3/pay/partner/transactions/out-trade-no/" + orderNo,
Map.of("sp_mchid", configDto.getMerchantId(), "sub_mchid", subMerchantId));
log.info("微信查询订单,订单号:{} 响应:{}", orderNo, resp);
JSONObject res = new JSONObject();
res.put("orderNo", orderNo);
JSONObject object = JSONObject.parseObject(resp);
String tradeState = object.getString("trade_state");
res.put("message", object.getString("trade_state_desc"));
if (PAY_SUCCESS.equals(tradeState)) {
res.put("status", "TRADE_SUCCESS");
return res;
}
if ("USERPAYING".equals(tradeState)) {
res.put("status", "TRADE_AWAIT");
return res;
}
res.put("status", "TRADE_FAIL");
return res;
} catch (Exception e) {
log.error("微信查询订单异常: orderNo = {}, e = {}", orderNo, e.getMessage());
throw new CzgException("微信查询订单异常");
}
}
/**
* 退款
*
* @param configDto 配置
* @param paramsDto 参数
* SUCCESS: 退款成功
* CLOSED: 退款关闭
* PROCESSING: 退款处理中
* ABNORMAL: 退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往服务商平台-交易中心,手动处理此笔退款
*/
public static Map<String, Object> refundOrder(WechatPayConfigDto configDto, RefundParamsDto paramsDto) {
try {
if (configDto == null) {
configDto = WechatPayConfigDto.getDefaultConfig();
}
JSONObject refundParam = new JSONObject();
refundParam.put("sub_mchid", paramsDto.getMerchantId());
refundParam.put("out_trade_no", paramsDto.getOrderNo());
refundParam.put("out_refund_no", paramsDto.getRefundOrderNo());
refundParam.put("reason", paramsDto.getRefundReason());
refundParam.put("notify_url", paramsDto.getRefundNotifyUrl() + "/" + PayCst.Platform.WECHAT);
JSONObject amount = new JSONObject();
amount.put("total", paramsDto.getOrderAmount());
amount.put("refund", paramsDto.getRefundAmount());
amount.put("currency", "CNY");
refundParam.put("amount", amount);
String resp = WechatReqUtils.postReq(configDto, "/v3/refund/domestic/refunds", refundParam.toJSONString());
log.info("微信退款,订单号:{} 响应:{}", paramsDto.getOrderNo(), resp);
JSONObject object = JSONObject.parseObject(resp);
JSONObject res = new JSONObject();
res.put("mchRefundNo", object.getString("out_refund_no"));
res.put("refundOrderId", object.getString("refund_id"));
res.put("oriPayOrderId", object.getString("out_trade_no"));
res.put("mercNo", paramsDto.getMerchantId());
res.put("refundReason", paramsDto.getRefundReason());
res.put("payType", PayCst.Platform.WECHAT);
res.put("refundTime", object.getString("success_time"));
switch (object.getString("status")) {
case "SUCCESS":
res.put("status", "SUCCESS");
break;
case "CLOSED":
res.put("status", "CLOSED");
break;
case "PROCESSING":
res.put("status", "ING");
break;
case "ABNORMAL":
res.put("status", "INIT");
break;
default:
res.put("status", "FAIL");
break;
}
JSONObject resAmount = object.getJSONObject("amount");
if (resAmount != null) {
res.put("refundAmt", resAmount.getLong("refund"));
res.put("oriAmount", resAmount.getLong("total"));
}
return res;
} catch (Exception e) {
log.error("微信退款异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage());
throw new CzgException("微信退款异常");
}
}
/**
* 将String转换为InputStream
*
* @param str 待转换的字符串
* @return 转换后的InputStream
*/
private static InputStream stringToInputStream(String str) {
if (str == null || str.isEmpty()) {
return new ByteArrayInputStream(new byte[0]);
}
// 核心先转字节数组再封装为ByteArrayInputStream
byte[] byteArray = str.getBytes(StandardCharsets.UTF_8);
return new ByteArrayInputStream(byteArray);
}
private static String signBarPayParam(WechatPayConfigDto configDto, Map<String, Object> params) {
TreeMap<String, Object> sortedParams = new TreeMap<>(params);
String sortParam = sortedParams.entrySet().stream()
// 将每个键值对转换为 "key=value" 格式的字符串
.map(entry -> entry.getKey() + "=" + (entry.getValue() == null ? "" : entry.getValue()))
// 使用 "&" 连接所有转换后的字符串
.collect(Collectors.joining("&"));
log.info("微信条码支付 加密前参数: {}", sortParam);
String signStr = sortParam + "&key=" + configDto.getApiV2Key();
return SecureUtil.md5(signStr).toUpperCase();
}
/**
* 添加元素,包括空值
*/
private static void addElementIfNotEmpty(Element parent, String name, Object value) {
Element element = parent.addElement(name);
element.addText(value == null ? "" : String.valueOf(value));
}
public static void main(String[] args) {
// barPay(null, new PayParamsDto()
// .setMerchantId("1738216504")
// .setOrderNo("sa101293120sss1")
// .setTitle("1213")
// .setBody("1213")
// .setAmount(1L)
// .setAppId("wxd88fffa983758a30")
// .setClientIp("127.0.0.1")
// .setBarCode("130013153082460022"));
// Map<String, Object> sss1 = queryOrder(null, "sa101293120sss1", "1738216504");
// System.out.println(sss1);
refundOrder(null, new RefundParamsDto()
.setMerchantId("1738216504")
.setOrderNo("sa101293120sss1")
.setRefundOrderNo("sa101293120sss1")
.setOrderAmount(1L)
.setRefundAmount(1L)
.setRefundReason("测试")
.setRefundNotifyUrl("https://www.baidu.com"));
}
}

View File

@@ -3,17 +3,18 @@ package com.czg.third.wechat;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.czg.dto.req.WechatNotifyReqDto;
import com.czg.exception.CzgException;
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.core.util.NonceUtil;
import lombok.extern.slf4j.Slf4j;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
@@ -53,19 +54,22 @@ public class WechatReqUtils {
HttpRequest request = switch (method) {
case "POST" -> HttpUtil.createPost(configDto.getDomain() + url)
.header("Authorization", authorization)
.header("Content-Type", "application/json")
.header("Wechatpay-Serial", configDto.getPublicKeyId())
.charset(StandardCharsets.UTF_8)
.contentType("application/json")
.body(body);
case "GET" -> HttpUtil.createGet(configDto.getDomain() + url)
.header("Authorization", authorization)
.header("Content-Type", "application/json")
.header("Wechatpay-Serial", configDto.getPublicKeyId());
.header("Wechatpay-Serial", configDto.getPublicKeyId())
.charset(StandardCharsets.UTF_8)
.contentType("application/json");
default -> throw new CzgException("不支持的请求方法");
};
log.info("微信支付请求url = {} \nauthorization: {}", request.getUrl(), authorization);
HttpResponse response = request.execute();
String s = response.body();
log.info("微信支付请求:url = {}, method: {}, body: {}, resp: {}", url, method, body, s);
log.info("微信支付请求:\n\turl = {}\n\tmethod: {}\n\tbody: {}\n\tresp: {}", url, method, body, s);
return s;
}
@@ -92,15 +96,37 @@ public class WechatReqUtils {
Config config = WechatConfig.getRsaConfig(configDto);
Signer signer = config.createSigner();
String signature = signer.sign(encryptStr).getSign();
log.info("微信签名 encryptStr = {},\nsignature{}", encryptStr, signature);
log.info("微信签名 encryptStr = \n{} \nsignature{}", encryptStr, signature);
return signature;
}
/**
* 解密微信回调报文
*
* @param configDto 配置
* @param reqDto 请求报文
* @return 解密后的报文
*/
public static String decryptRespParam(WechatPayConfigDto configDto, WechatNotifyReqDto reqDto) {
if (configDto == null) {
configDto = WechatPayConfigDto.getDefaultConfig();
}
WechatAesUtil aesUtil = new WechatAesUtil(configDto.getApiV3Key().getBytes(StandardCharsets.UTF_8));
try {
return aesUtil.decryptToString(
reqDto.getResource().getAssociatedData() == null ? new byte[0] : reqDto.getResource().getAssociatedData().getBytes(StandardCharsets.UTF_8),
reqDto.getResource().getNonce().getBytes(StandardCharsets.UTF_8), reqDto.getResource().getCiphertext());
} catch (Exception e) {
log.error("【微信支付回调】解密失败 {}", reqDto);
throw new CzgException("解密失败");
}
}
/**
* 获取随机串
*/
private static String getNonceStr() {
return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
return NonceUtil.createNonce(32);
}
/**

View File

@@ -21,6 +21,11 @@ public class WechatPayConfigDto {
*/
private String apiV3Key;
/**
* Api V2 密钥
*/
private String apiV2Key;
/**
* 商户证书序列号
*/

View File

@@ -35,6 +35,9 @@ public class WechatEntryBankAccountReqDto {
@JSONField(name = "account_name")
private String accountName;
@JSONField(name = "bank_address_code")
private String bankAddressCode;
/**
* 【必填】
* 开户银行

View File

@@ -55,7 +55,8 @@ public class WechatEntryStoreInfoReqDto {
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "store_entrance_pic")
private List<String> storeEntrancePic;
// private List<String> storeEntrancePic;
private String storeEntrancePic;
/**
* 【必填】
@@ -64,7 +65,8 @@ public class WechatEntryStoreInfoReqDto {
* 2、请填写通过图片上传API预先上传图片生成好的MediaID。
*/
@JSONField(name = "indoor_pic")
private List<String> indoorPic;
// private List<String> indoorPic;
private String indoorPic;
/**
* 【选填】

View File

@@ -1,124 +0,0 @@
package com.czg.entity.req;
import lombok.Data;
import lombok.NonNull;
/**
* @author ww
*/
@Data
public class CzgBaseReq {
//必填范围
/**
* 订单标题
*/
private String subject;
/**
* 订单描述 String(256)
*/
private String body;
/**
* 交易金额
*/
private Long amount;
/**
* 货币类型 cny
*/
private String currency = "cny";
/**
* 商户订单号 String(30)
* 操作方式+雪花算法
* 收银机客户端 PC+雪花ID
* 微信小程序 WX+雪花ID
* 支付宝小程序 ALI+雪花ID
* PC管理端 WEB+雪花ID
* APP管理端 APP+雪花ID
* <p>
* 退款 re+雪花ID
*/
private String mchOrderNo;
/**
* 门店编号 tb_shop_merchant 的 store_id
*/
private String storeId;
//非必填项
/**
* 订单备注 String(50)
*/
private String buyerRemark;
/**
* 异步通知地址 String(128)
* 支付结果异步回调URL,只有传了该值才会发起回调
*/
private String notifyUrl;
/**
* 失效时间 int 15
* 订单失效时间,单位分钟,默认15小时.
* 取值范围 5-1440 分钟
* 订单在(创建时间+失效时间)后失效
*/
private Integer expiredTime;
/**
* 分账模式:
* 0-该笔订单不允许分账[默认],
* 1-实时分账
* 2-延时分账
*/
private Integer divisionMode;
/**
* 分账详情
*/
private String divisionDetail;
/**
* 扩展参数 String(512)
* 商户扩展参数,回调时会原样返回
* * 扩展参数
* * {
* * "pay_type": "order/vip"
* * }
*/
private String extParam;
/**
* 花呗分期数
* 支付宝交易时可传 而且金额需要大于或等于 100.00元时生效
* 3/6/12
*/
private Integer hbFqNum;
/**
* 卖家是否承担手续费
* 100卖家承担手续费
* 0买家承担手续费
*/
private Integer hbFqPercent;
/**
* 是否禁用信用卡
* -1不禁用 1禁用
* 不传默认为不限制
*/
private Integer limitPay;
public CzgBaseReq() {
}
public CzgBaseReq(String mchOrderNo, Long amount, String body,
String buyerRemark, String extParam) {
this.mchOrderNo = mchOrderNo;
this.body = body;
this.amount = amount;
this.buyerRemark = buyerRemark;
this.extParam = extParam;
}
public void assignMerchant(@NonNull String storeId, @NonNull String subject, @NonNull String notifyUrl) {
this.storeId = storeId;
this.subject = subject;
this.notifyUrl = notifyUrl;
}
}

View File

@@ -1,39 +0,0 @@
package com.czg.entity.req;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
/**
* h5支付请求参数
*
* @author ww
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CzgH5PayReq extends CzgBaseReq {
//必填范围
/**
* 用户IP 支付的用户IP
*/
private String clientIp;
private String payType;
//?
private String openId;
//非必填范围
/**
* 跳转通知地址
* 支付结果同步跳转通知URL
*/
private String returnUrl;
public CzgH5PayReq(@NonNull String mchOrderNo, @NonNull Long amount, String body, @NonNull String clientIp,
String returnUrl, String buyerRemark, @NonNull String extParam) {
super(mchOrderNo, amount, body, buyerRemark, extParam);
this.clientIp = clientIp;
this.returnUrl = returnUrl;
}
}

View File

@@ -1,71 +0,0 @@
package com.czg.entity.req;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
/**
* 公众号/生活号/银联js支付
*
* @author ww
* <p>
* ● 码牌、台卡、立牌等
* 用户通过扫描微信/支付宝/云闪付APP静态二维码输入订单金额进行付款动作。
* ● 公众号 / 生活号商城
* 用户通过公众号下单,输入密码完成付款动作。适用于自有公众号主体交易
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CzgJsPayReq extends CzgBaseReq {
//必填范围
/**
* 用户唯一标识 String(30)
* 微信支付时传入用户的openId
* 支付宝支付和银联支付时传入用户的userId
*/
private String userId;
/**
* 用户IP
* 需要传付款用户客户端IP地址
*/
private String clientIp;
/**
* 微信 WECHAT
* 支付宝 ALIPAY
* 银联云闪付 UNIONPAY
*/
private String payType;
//非必填范围
/**
* 子商户appid ,微信付款支付的时候 需要上送
*/
private String subAppid;
/**
* 跳转通知地址
* 支付结果同步跳转通知URL
*/
private String returnUrl;
/**
* 银联js支付成功前端跳转
*/
private String frontUrl;
/**
* 银联js支付失败前端跳转地址
*/
private String frontFailUrl;
public CzgJsPayReq(@NonNull String mchOrderNo,
@NonNull Long amount, String body,
@NonNull String openId, @NonNull String clientIp,
String returnUrl, String buyerRemark,@NonNull String extParam) {
super(mchOrderNo, amount, body, buyerRemark, extParam);
this.userId = openId;
this.clientIp = clientIp;
this.returnUrl = returnUrl;
}
}

View File

@@ -1,63 +0,0 @@
package com.czg.entity.req;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
/**
* 小程序支付
*
* @author ww
* 自有小程序拉起支付
* 自有小程序拉起服务商小程序,(微信)半屏小程序支付
* 半屏小程序需要在商户自己的小程序中的半屏小程序配置里面申请 否则会拉起全屏小程序支付
* <p>
* 半屏小程序支付适用场景是商户自己的小程序被纳入微信实物电商类型小程序导致间联商户无法绑定这类的小程序APPID
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CzgLtPayReq extends CzgBaseReq {
//必填范围
/**
* 用户唯一标识 String(30)
* 微信支付时,传入用户的 openId
* 支付宝支付和银联支付时,传入用户的 userId
*/
private String userId;
private String payType;
/**
* 用户 IP 支付的用户 IP
*/
private String clientIp;
//非必填范围
/**
* 跳转通知地址
* 支付结果同步跳转通知 URL
*/
private String returnUrl;
/**
* 子商户 appid ,微信付款支付的时候 需要上送
* isScreen 为 false 的情况下需要传入
*/
private String subAppid;
/**
* 是否半屏
* 是否使用半屏小程序,默认为 false
* 前提小程序被纳入了实物电商类型的小程序,间联商户无法绑定这类的小程序的 appid
*/
private boolean isScreen;
public CzgLtPayReq(@NonNull String mchOrderNo, @NonNull Long amount, @NonNull String payType,
String body, @NonNull String openId, @NonNull String clientIp,
String returnUrl, String buyerRemark, @NonNull String extParam) {
super(mchOrderNo, amount, body, buyerRemark, extParam);
this.userId = openId;
this.payType = "aliPay".equals(payType) ? "ALIPAY" : "WECHAT";
this.clientIp = clientIp;
this.returnUrl = returnUrl;
}
}

View File

@@ -1,37 +0,0 @@
package com.czg.entity.req;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
/**
* 反扫请求参数
*
* @author ww
* <p>
* 被扫免密同步返回支付结果,不推送异步通知。
* 被扫输密,推送异步通知。
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CzgMicroPayReq extends CzgBaseReq {
//必填范围
/**
* 付款码信息 String(30)
* 扫码设备获取微信或支付宝上付款的信息
*/
private String authCode;
//非必填范围
/**
* 子商户appid ,微信付款支付的时候 需要上送
*/
private String subAppid;
public CzgMicroPayReq(@NonNull String mchOrderNo, @NonNull Long amount, String body,
@NonNull String authCode, String buyerRemark, @NonNull String extParam) {
super(mchOrderNo, amount, body, buyerRemark, extParam);
this.authCode = authCode;
}
}

View File

@@ -1,35 +0,0 @@
package com.czg.entity.req;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
/**
* 正扫支付请求参数
*
* @author ww
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CzgScanPayReq extends CzgBaseReq {
// 必填项
/**
* 用户IP 支付的用户IP
*/
private String clientIp;
//非必填项
/**
* 跳转通知地址
* String(128)
*/
private String returnUrl;
public CzgScanPayReq(@NonNull String mchOrderNo, @NonNull Long amount, String body,
@NonNull String clientIp, String returnUrl, String buyerRemark, @NonNull String extParam) {
super(mchOrderNo, amount, body, buyerRemark, extParam);
this.clientIp = clientIp;
this.returnUrl = returnUrl;
}
}

View File

@@ -9,7 +9,7 @@
<version>1.0.0</version>
</parent>
<artifactId>czg-pay</artifactId>
<artifactId>poly-pay</artifactId>
<properties>
<maven.compiler.source>21</maven.compiler.source>

View File

@@ -8,11 +8,12 @@ import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.czg.entity.CzgBaseReqParams;
import com.czg.entity.CzgBaseRespParams;
import com.czg.entity.req.*;
import com.czg.entity.PolyBaseReq;
import com.czg.entity.PolyBaseResp;
import com.czg.entity.resp.*;
import com.czg.enums.CzgPayEnum;
import com.czg.pay.CzgPayBaseReq;
import com.czg.pay.CzgRefundReq;
import com.czg.resp.CzgRespCode;
import com.czg.resp.CzgResult;
import com.czg.utils.AssertUtil;
@@ -26,10 +27,10 @@ import java.util.stream.Collectors;
/**
* @author ww
* @description 超掌柜支付类
* @description 聚合支付类
*/
@Slf4j
public class CzgPayUtils {
public class PolyPayUtils {
/**
* h5支付
@@ -39,8 +40,8 @@ public class CzgPayUtils {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* CzgResult<CzgH5PayResp>
*/
public static CzgResult<Map<String, Object>> h5Pay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgH5PayReq bizData) {
return execPayResult(sendCzg(domain.concat(CzgPayEnum.H5PAY.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, bizData), CzgH5PayResp.class));
public static CzgResult<Map<String, Object>> h5Pay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgPayBaseReq<?> bizData) {
return execPayResult(sendPolyPay(domain.concat(CzgPayEnum.H5_PAY.getUri()), PolyBaseReq.getInstance(appId, appSecret, bizData), CzgH5PayResp.class));
}
/**
@@ -51,8 +52,8 @@ public class CzgPayUtils {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* CzgResult<CzgJsPayResp>
*/
public static CzgResult<Map<String, Object>> jsPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgJsPayReq bizData) {
return execPayResult(sendCzg(domain.concat(CzgPayEnum.JSPAY.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, bizData), CzgJsPayResp.class));
public static CzgResult<Map<String, Object>> jsPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgPayBaseReq<?> bizData) {
return execPayResult(sendPolyPay(domain.concat(CzgPayEnum.JS_PAY.getUri()), PolyBaseReq.getInstance(appId, appSecret, bizData), CzgJsPayResp.class));
}
/**
@@ -63,8 +64,8 @@ public class CzgPayUtils {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* CzgResult<CzgLtPayResp>
*/
public static CzgResult<Map<String, Object>> ltPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgLtPayReq bizData) {
return execPayResult(sendCzg(domain.concat(CzgPayEnum.LTPAY.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, bizData), CzgLtPayResp.class));
public static CzgResult<Map<String, Object>> ltPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgPayBaseReq<?> bizData) {
return execPayResult(sendPolyPay(domain.concat(CzgPayEnum.LT_PAY.getUri()), PolyBaseReq.getInstance(appId, appSecret, bizData), CzgLtPayResp.class));
}
/**
@@ -75,8 +76,8 @@ public class CzgPayUtils {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* CzgResult<CzgScanPayResp>
*/
public static CzgResult<Map<String, Object>> scanPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgScanPayReq bizData) {
return execPayResult(sendCzg(domain.concat(CzgPayEnum.SCANPAY.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, bizData), CzgScanPayResp.class));
public static CzgResult<Map<String, Object>> scanPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgPayBaseReq<?> bizData) {
return execPayResult(sendPolyPay(domain.concat(CzgPayEnum.SCAN_PAY.getUri()), PolyBaseReq.getInstance(appId, appSecret, bizData), CzgScanPayResp.class));
}
/**
@@ -87,8 +88,8 @@ public class CzgPayUtils {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* CzgResult<CzgMicroPayResp>
*/
public static CzgResult<Map<String, Object>> microPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgMicroPayReq bizData) {
return execPayResult(sendCzg(domain.concat(CzgPayEnum.MICROPAY.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, bizData), CzgMicroPayResp.class));
public static CzgResult<Map<String, Object>> microPay(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgPayBaseReq<?> bizData) {
return execPayResult(sendPolyPay(domain.concat(CzgPayEnum.MICRO_PAY.getUri()), PolyBaseReq.getInstance(appId, appSecret, bizData), CzgMicroPayResp.class));
}
/**
@@ -105,7 +106,7 @@ public class CzgPayUtils {
JSONObject queryPayOrder = new JSONObject();
queryPayOrder.put("payOrderId", payOrderId);
queryPayOrder.put("mchOrderNo", mchOrderNo);
return sendCzg(domain.concat(CzgPayEnum.TRADE.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, queryPayOrder), CzgBaseResp.class);
return sendPolyPay(domain.concat(CzgPayEnum.TRADE.getUri()), PolyBaseReq.getInstance(appId, appSecret, queryPayOrder), CzgBaseResp.class);
}
@@ -117,7 +118,7 @@ public class CzgPayUtils {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
*/
public static CzgResult<CzgRefundResp> refundOrder(@NonNull String domain, @NonNull String appId, @NonNull String appSecret, CzgRefundReq bizData) {
return sendCzg(domain.concat(CzgPayEnum.REFUND.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, bizData), CzgRefundResp.class);
return sendPolyPay(domain.concat(CzgPayEnum.REFUND.getUri()), PolyBaseReq.getInstance(appId, appSecret, bizData), CzgRefundResp.class);
}
/**
@@ -134,23 +135,23 @@ public class CzgPayUtils {
JSONObject queryPayOrder = new JSONObject();
queryPayOrder.put("mchRefundNo", mchRefundNo);
queryPayOrder.put("refundOrderId", refundOrderId);
return sendCzg(domain.concat(CzgPayEnum.QUERY_REFUND.getUri()), CzgBaseReqParams.getInstance(appId, appSecret, queryPayOrder), CzgRefundResp.class);
return sendPolyPay(domain.concat(CzgPayEnum.QUERY_REFUND.getUri()), PolyBaseReq.getInstance(appId, appSecret, queryPayOrder), CzgRefundResp.class);
}
/**
* 回调数据处理
*/
public static JSONObject getCzg(CzgBaseRespParams respParams) {
AssertUtil.isNull(respParams, "超掌柜交易 回调数据为空");
log.info("超掌柜交易请求响应,{}", respParams);
public static JSONObject getCzg(PolyBaseResp respParams) {
AssertUtil.isNull(respParams, "聚合交易 回调数据为空");
log.info("聚合交易请求响应,{}", respParams);
if (!"000000".equals(respParams.getCode())) {
log.error("超掌柜回调响应失败,{}", respParams);
log.error("聚合回调响应失败,{}", respParams);
return null;
}
// if (StrUtil.isNotBlank(respParams.getSign())) {
// if (validateSign(respParams.getSign(), respParams.getBizData())) {
// log.error("超掌柜回调 验签失败");
// log.error("聚合回调 验签失败");
// }
// }
return JSONObject.parse(respParams.getBizData());
@@ -168,19 +169,19 @@ public class CzgPayUtils {
* "data": "返回Json数据",
* }
*/
private static <T> CzgResult<T> sendCzg(String url, CzgBaseReqParams params, Class<T> clazz) {
private static <T> CzgResult<T> sendPolyPay(String url, PolyBaseReq params, Class<T> clazz) {
CzgResult<T> result = CzgResult.success();
Map<String, Object> reqMap = BeanUtil.beanToMap(params, false, false);
params.setSign(MD5.create().digestHex(sortFields(new TreeMap<>(reqMap))));
log.info("超掌柜交易请求参数,{}", JSONObject.toJSONString(params));
log.info("聚合交易请求参数,{}", JSONObject.toJSONString(params));
try (HttpResponse resp = HttpRequest.post(url).body(JSONObject.toJSONString(params)).execute()) {
if (resp.isOk()) {
// 获取响应体
String respStr = resp.body();
if (StrUtil.isNotEmpty(respStr)) {
log.info("超掌柜交易请求响应元数据,{}", respStr);
CzgBaseRespParams respParams = JSONObject.parseObject(respStr, CzgBaseRespParams.class);
log.info("超掌柜交易请求响应,{}", respParams);
log.info("聚合交易请求响应元数据,{}", respStr);
PolyBaseResp respParams = JSONObject.parseObject(respStr, PolyBaseResp.class);
log.info("聚合交易请求响应,{}", respParams);
result.setCode("000000".equals(respParams.getCode()) ? 200 : Integer.parseInt(respParams.getCode()));
result.setMsg(respParams.getMsg());
@@ -194,15 +195,15 @@ public class CzgPayUtils {
}
} else {
result.setCode(resp.getStatus());
result.setMsg("超掌柜交易请求失败");
log.error("超掌柜交易请求失败,状态码: {}", resp.getStatus());
result.setMsg("聚合交易请求失败");
log.error("聚合交易请求失败,状态码: {}", resp.getStatus());
}
} else {
result.setCode(resp.getStatus());
result.setMsg("超掌柜交易请求失败");
result.setMsg("聚合交易请求失败");
}
} catch (Exception e) {
log.error("超掌柜交易请求异常", e);
log.error("聚合交易请求异常", e);
}
return result;
}
@@ -221,7 +222,7 @@ public class CzgPayUtils {
private static String sortFields(TreeMap<String, Object> map) {
if (CollectionUtil.isEmpty(map)) {
log.error("超掌柜支付参数为空!!!");
log.error("聚合支付参数为空!!!");
throw new RuntimeException("参数为空");
}
String sortParam = map.entrySet().stream()

View File

@@ -12,7 +12,7 @@ import lombok.Data;
* @author ww
*/
@Data
public class CzgBaseReqParams {
public class PolyBaseReq {
/**
* 应用ID tb_shop_merchant 表中的 app_id
@@ -69,7 +69,7 @@ public class CzgBaseReqParams {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* @param bizData JSON 形式的字符串
*/
public CzgBaseReqParams(String appId, String bizData, String appSecret) {
public PolyBaseReq(String appId, String bizData, String appSecret) {
this.appId = appId;
this.bizData = bizData;
this.appSecret = appSecret;
@@ -82,8 +82,8 @@ public class CzgBaseReqParams {
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
* @param bizData JSON 形式的字符串
*/
public static CzgBaseReqParams getInstance(String appId, String appSecret, Object bizData) {
return new CzgBaseReqParams(appId, ObjectUtil.isNotEmpty(bizData) ? JSONObject.toJSONString(bizData) : "", appSecret);
public static PolyBaseReq getInstance(String appId, String appSecret, Object bizData) {
return new PolyBaseReq(appId, ObjectUtil.isNotEmpty(bizData) ? JSONObject.toJSONString(bizData) : "", appSecret);
}
}

View File

@@ -6,7 +6,7 @@ import lombok.Data;
* @author ww
*/
@Data
public class CzgBaseRespParams {
public class PolyBaseResp {
/**

View File

@@ -8,11 +8,11 @@ import lombok.Getter;
@Getter
public enum CzgPayEnum {
SCANPAY("/api/open/payment/scanpay", "PC扫码支付"),
MICROPAY("/api/open/payment/micropay", "聚合反扫B扫C/ 快捷收款"),
JSPAY("/api/open/payment/jspay", "公众号/生活号/银联js支付"),
LTPAY("/api/open/payment/ltpay", "小程序支付"),
H5PAY("/api/open/payment/h5pay", "手机网页支付"),
SCAN_PAY("/api/open/payment/scanpay", "PC扫码支付"),
MICRO_PAY("/api/open/payment/micropay", "聚合反扫B扫C/ 快捷收款"),
JS_PAY("/api/open/payment/jspay", "公众号/生活号/银联js支付"),
LT_PAY("/api/open/payment/ltpay", "小程序支付"),
H5_PAY("/api/open/payment/h5pay", "手机网页支付"),
TRADE("/api/open/query/trade", "订单状态查询"),
REFUND("/api/open/order/refund", "统一退款 D0退款需要使用平台户退款"),

View File

@@ -12,7 +12,7 @@
<name>third sdk</name>
<description>第三方内容</description>
<modules>
<module>czg-pay</module>
<module>poly-pay</module>
<module>aggregation-pay</module>
</modules>
<artifactId>cash-sdk</artifactId>
@@ -29,5 +29,10 @@
<artifactId>cash-common-tools</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.czg</groupId>
<artifactId>cash-common-service</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,14 @@
package com.czg.service.account.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.account.entity.QuickMenu;
/**
* 悬浮窗配置 映射层。
*
* @author ww
* @since 2025-12-29
*/
public interface QuickMenuMapper extends BaseMapper<QuickMenu> {
}

View File

@@ -14,9 +14,9 @@ import com.czg.config.RedisCst;
import com.czg.constants.ParamCodeCst;
import com.czg.exception.CzgException;
import com.czg.resp.CzgResult;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.CallQueueMapper;
import com.czg.service.account.mapper.CallTableMapper;
import com.czg.service.account.util.FunUtil;
import com.czg.service.account.util.WechatMiniMsgUtil;
import com.czg.system.dto.SysParamsDTO;
import com.czg.system.service.SysParamsService;
@@ -51,10 +51,10 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
@Resource
private ShopUserService shopUserService;
@Resource
private FunUtil funUtil;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RedisService redisService;
@Resource
private ShopInfoService shopInfoService;
@Resource
private CallConfigService callConfigService;
@@ -228,13 +228,13 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
}
private String getCallNumber(Long shopId, CallTable callTable) {
return funUtil.runFunAndCheckKey(() -> {
return redisService.runFunAndCheckKey(() -> {
String callNumKey = RedisCst.getTableCallNumKey(shopId, callTable.getId());
String value = stringRedisTemplate.opsForValue().get(callNumKey);
AtomicReference<String> newVal = new AtomicReference<>("");
// 初始化
if (StrUtil.isBlank(value)) {
Boolean setFlag = FunUtil.runFunAndRetry(() -> stringRedisTemplate.opsForValue().setIfAbsent(callNumKey, callTable.getStart().toString()), flag -> !flag,
Boolean setFlag = RedisService.runFunAndRetry(() -> stringRedisTemplate.opsForValue().setIfAbsent(callNumKey, callTable.getStart().toString()), flag -> !flag,
_ -> newVal.set(stringRedisTemplate.opsForValue().get(callNumKey)));
if (setFlag) {

View File

@@ -0,0 +1,18 @@
package com.czg.service.account.service.impl;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.account.entity.QuickMenu;
import com.czg.account.service.QuickMenuService;
import com.czg.service.account.mapper.QuickMenuMapper;
import org.springframework.stereotype.Service;
/**
* 悬浮窗配置 服务层实现。
*
* @author ww
* @since 2025-12-29
*/
@Service
public class QuickMenuServiceImpl extends ServiceImpl<QuickMenuMapper, QuickMenu> implements QuickMenuService{
}

View File

@@ -17,6 +17,7 @@ import com.czg.constants.ParamCodeCst;
import com.czg.constants.ShopSwitchTypeEnum;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.order.service.ShopMerchantService;
import com.czg.resp.CzgResult;
import com.czg.sa.MyStpLogic;
import com.czg.sa.StpKit;
@@ -77,6 +78,8 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
private FreeDineConfigService freeDineConfigService;
@Resource
private ShopConfigService shopConfigService;
@Resource
private ShopMerchantService shopMerchantService;
@DubboReference
private SysParamsService sysParamsService;
@@ -99,7 +102,7 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
if (shopInfo == null) {
throw new CzgException("店铺不存在");
}
if (shopInfo.getExpireTime() != null && (DateUtil.date().toLocalDateTime().isAfter(shopInfo.getExpireTime()))) {
if (shopInfo.getExpireTime() != null && (LocalDateTime.now().isAfter(shopInfo.getExpireTime()))) {
throw new CzgException("店铺已过期,请联系商家");
}
if (SystemConstants.OneZero.ZERO == shopInfo.getOnSale() || shopInfo.getStatus() != SystemConstants.OneZero.ONE) {
@@ -324,15 +327,6 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
return false;
}
@Override
@CacheEvict(key = "#shopId")
public Boolean editEntry(Long shopId, String wechatMerchantId, String alipayMerchantId) {
ShopInfo shopInfo = new ShopInfo();
shopInfo.setWechatMerchantId(wechatMerchantId);
shopInfo.setAlipayMerchantId(alipayMerchantId);
return update(shopInfo, new QueryWrapper().eq(ShopInfo::getId, shopId));
}
@Override
public ShopDetailDTO detail(Long id) throws CzgException {
ShopInfo shopInfo = queryChain().eq(ShopInfo::getId, id == null ? StpKit.USER.getShopId() : id).one();

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