Merge branch 'test' into prod
# Conflicts: # cash-api/account-server/src/main/java/com/czg/controller/admin/AuthorizationController.java # cash-api/order-server/src/main/java/com/czg/controller/DistributionPayController.java # cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoCustomServiceImpl.java # cash-service/order-service/src/main/java/com/czg/service/order/service/impl/PayServiceImpl.java
This commit is contained in:
@@ -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> {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -29,6 +29,7 @@ import jakarta.annotation.Resource;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.*;
|
||||
@@ -41,7 +42,7 @@ import java.util.stream.Collectors;
|
||||
* @author zs
|
||||
* @since 2025-02-21
|
||||
*/
|
||||
@DubboService
|
||||
@Service
|
||||
public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable> implements CallTableService {
|
||||
@DubboReference
|
||||
private SysParamsService sysParamsService;
|
||||
@@ -51,10 +52,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 +229,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) {
|
||||
|
||||
@@ -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{
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.czg.service.account.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.czg.account.dto.merchant.ShopMerchantEditDTO;
|
||||
import com.czg.account.entity.ShopMerchant;
|
||||
import com.czg.account.service.ShopMerchantService;
|
||||
import com.czg.sa.StpKit;
|
||||
import com.czg.service.account.mapper.ShopMerchantMapper;
|
||||
import com.czg.utils.AssertUtil;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 第三方商户进件 服务层实现。
|
||||
*
|
||||
* @author Administrator
|
||||
* @since 2025-02-11
|
||||
*/
|
||||
@CacheConfig(cacheNames = "shop:merchant")
|
||||
@DubboService
|
||||
public class ShopMerchantServiceImpl extends ServiceImpl<ShopMerchantMapper, ShopMerchant> implements ShopMerchantService {
|
||||
|
||||
@Override
|
||||
public ShopMerchant detail(Integer shopId) {
|
||||
ShopMerchant one = queryChain().eq(ShopMerchant::getShopId, shopId).one();
|
||||
return one == null ? new ShopMerchant() : one;
|
||||
}
|
||||
|
||||
@CacheEvict(key = "#shopMerchantEditDTO.shopId")
|
||||
@Override
|
||||
public Boolean edit(ShopMerchantEditDTO shopMerchantEditDTO) {
|
||||
ShopMerchant shopMerchant = queryChain().eq(ShopMerchant::getShopId, shopMerchantEditDTO.getShopId()).one();
|
||||
if (shopMerchant == null) {
|
||||
shopMerchant = new ShopMerchant();
|
||||
shopMerchant.setShopId(shopMerchantEditDTO.getShopId());
|
||||
BeanUtil.copyProperties(shopMerchantEditDTO, shopMerchant);
|
||||
return save(shopMerchant);
|
||||
}
|
||||
BeanUtil.copyProperties(shopMerchantEditDTO, shopMerchant);
|
||||
return updateById(shopMerchant);
|
||||
}
|
||||
|
||||
@Cacheable(key = "#id")
|
||||
@Override
|
||||
public ShopMerchant getById(Serializable id) {
|
||||
ShopMerchant shopMerchant = getMapper().selectOneById(id);
|
||||
AssertUtil.isNull(shopMerchant, "暂未开通支付");
|
||||
return shopMerchant;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import com.czg.market.vo.InviteUserVO;
|
||||
import com.czg.market.vo.MemberConfigVO;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.service.account.mapper.ShopUserMapper;
|
||||
import com.czg.service.account.util.FunUtil;
|
||||
import com.czg.utils.FunUtils;
|
||||
import com.czg.utils.PageUtil;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
package com.czg.service.account.util;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FunUtil {
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
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) {
|
||||
log.info("工具类开始执行函数");
|
||||
R result = function.get();
|
||||
boolean flag = check.apply(result);
|
||||
|
||||
log.info("执行结果: {}", result);
|
||||
|
||||
while (flag && retryCount-- > 0) {
|
||||
log.info("执行函数失败, 剩余尝试次数{}", retryCount);
|
||||
result = function.get();
|
||||
log.info("执行结果: {}", result);
|
||||
flag = check.apply(result);
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
errFun.accept(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.account.mapper.QuickMenuMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -18,9 +18,8 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>pay-service</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<groupId>com.github.javen205</groupId>
|
||||
<artifactId>IJPay-All</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.czg.service.market.service.impl;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.constants.ParamCodeCst;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.service.RedisService;
|
||||
import com.czg.system.service.SysParamsService;
|
||||
import com.ijpay.core.kit.RsaKit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -14,7 +14,6 @@ import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 微信支付service
|
||||
@@ -80,7 +79,7 @@ public class AppWxServiceImpl extends BaseWx {
|
||||
// api支付证书公钥
|
||||
config.apiCert = payKeyMap.get(ParamCodeCst.Wechat.Pay.WX_API_CLIENT_CERT);
|
||||
try {
|
||||
config.privateKey = RsaKit.loadPrivateKey(config.apiCertKey);
|
||||
config.privateKey = SecureUtil.rsa(config.apiCertKey, null).getPrivateKey();
|
||||
} catch (Exception e) {
|
||||
log.warn("微信加载api证书失败");
|
||||
}
|
||||
@@ -98,10 +97,6 @@ public class AppWxServiceImpl extends BaseWx {
|
||||
config.refundNotifyUrl = "";
|
||||
config.transferNotifyUrl = payKeyMap.get(ParamCodeCst.System.NATIVE_NOTIFY_URL) + "/wx/transfer";
|
||||
}
|
||||
|
||||
public BaseWx getAppService() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>pay-service</artifactId>
|
||||
<artifactId>market-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>market-service</artifactId>
|
||||
<artifactId>pay-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- 订单服务依赖消息队列 从 market 拿 -->
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.czg.service.order.dto;
|
||||
|
||||
import com.czg.dto.req.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class AggregateMerchantVO extends AggregateMerchantDto{
|
||||
|
||||
private String shopName;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* {@link com.czg.PayCst.EntryStatus}
|
||||
* 微信状态
|
||||
* WAIT 待提交 INIT 待处理 AUDIT 审核中 SIGN 待签约 REJECTED 失败 FINISH 已完成
|
||||
*/
|
||||
private String wechatStatus;
|
||||
|
||||
/**
|
||||
* 支付宝账号
|
||||
*/
|
||||
private String alipayAccount;
|
||||
/**
|
||||
* 商户编号(在当前系统唯一)
|
||||
*/
|
||||
private String merchantCode;
|
||||
/**
|
||||
* 【必填】
|
||||
* 商户类型
|
||||
* 0: 个体商户;
|
||||
* 1: 企业商户;
|
||||
* 3: 小微商户 暂不支持
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 【必填】
|
||||
* 商户简称--企业、个体必填
|
||||
*/
|
||||
private String shortName;
|
||||
|
||||
/**
|
||||
* 微信进件错误信息
|
||||
*/
|
||||
private String wechatErrorMsg;
|
||||
/**
|
||||
* 微信进件签名地址
|
||||
*/
|
||||
private String wechatSignUrl;
|
||||
private String wechatApplyId;
|
||||
private String alipayOrderId;
|
||||
|
||||
/**
|
||||
* {@link com.czg.PayCst.EntryStatus}
|
||||
* 支付宝状态
|
||||
* WAIT 待提交 INIT 待处理 AUDIT 审核中 SIGN 待签约 REJECTED 失败 FINISH 已完成
|
||||
*/
|
||||
private String alipayStatus;
|
||||
|
||||
/**
|
||||
* 支付宝进件错误信息
|
||||
*/
|
||||
private String alipayErrorMsg;
|
||||
/**
|
||||
* 支付宝进件签名地址
|
||||
*/
|
||||
private String alipaySignUrl;
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.czg.service.order.dto;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
* @author ww
|
||||
*/
|
||||
@Data
|
||||
public class CreateOrderDTO {
|
||||
@NotBlank(message = "桌号不能为空")
|
||||
private String tableCode;
|
||||
@NotBlank(message = "用餐模式 堂食 dine-in 外带 take-out 外卖 take-away")
|
||||
private String dineMode;
|
||||
/**
|
||||
* 平台类型
|
||||
* 微信小程序 WX
|
||||
* 支付宝小程序 ALI
|
||||
* 收银机客户端 PC
|
||||
* PC管理端 APC
|
||||
* APP管理端 APP
|
||||
*/
|
||||
@NotBlank(message = "平台类型不能为空")
|
||||
private String platformType;
|
||||
|
||||
/**
|
||||
* 是否使用了霸王餐
|
||||
*/
|
||||
private boolean isFreeDine = false;
|
||||
|
||||
private String remark;
|
||||
|
||||
// 使用的积分抵扣数量
|
||||
private Integer pointsNum;
|
||||
|
||||
// 使用的优惠券
|
||||
@Valid
|
||||
private List<UserCouponInfoDTO> userCouponInfos = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.czg.service.order.dto;
|
||||
|
||||
import com.czg.BaseQueryParam;
|
||||
import com.czg.utils.CzgStrUtils;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
/**
|
||||
* 进件查询参数
|
||||
* @author ww
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MerchantQueryDTO extends BaseQueryParam {
|
||||
|
||||
/**
|
||||
* 商户类型
|
||||
* 0: 个体商户;
|
||||
* 1: 企业商户;
|
||||
*/
|
||||
private String userType;
|
||||
/**
|
||||
* 店铺名称 模糊查询
|
||||
*/
|
||||
private String shopName;
|
||||
/**
|
||||
* 进件状态
|
||||
* {@link com.czg.PayCst.EntryStatus}
|
||||
* WAIT 待提交
|
||||
* INIT 待处理
|
||||
* AUDIT 待审核
|
||||
* SIGN 待签约
|
||||
* FINISH 已完成
|
||||
* REJECTED 失败
|
||||
*/
|
||||
private String status;
|
||||
/**
|
||||
* 支付宝账号
|
||||
*/
|
||||
private String alipayAccount;
|
||||
|
||||
public String getUserType() {
|
||||
return CzgStrUtils.getStrOrNull(userType);
|
||||
}
|
||||
|
||||
public String getShopName() {
|
||||
return CzgStrUtils.getStrOrNull(shopName);
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return CzgStrUtils.getStrOrNull(status);
|
||||
}
|
||||
|
||||
public String getAlipayAccount() {
|
||||
return CzgStrUtils.getStrOrNull(alipayAccount);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.czg.service.order.dto;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 支付接收参数 实体类
|
||||
*
|
||||
* @author ww
|
||||
* @description
|
||||
*/
|
||||
@Data
|
||||
public class RechargeDTO {
|
||||
@NotNull(message = "店铺不能为空")
|
||||
private Long shopId;
|
||||
private Long shopUserId;
|
||||
|
||||
/**
|
||||
* 充值金额id
|
||||
*/
|
||||
private Long rechargeDetailId;
|
||||
@DecimalMin("0.01")
|
||||
private BigDecimal amount;
|
||||
private Integer allPack;
|
||||
|
||||
/**
|
||||
* 跳转地址
|
||||
*/
|
||||
private String returnUrl;
|
||||
/**
|
||||
* 平台类型 pc 收银机客户端 wechat 微信小程序 alipay 支付宝小程序 admin-pc PC管理端 admin-app APP管理端
|
||||
*/
|
||||
private String platformType;
|
||||
|
||||
private String openId;
|
||||
|
||||
private String buyerRemark;
|
||||
|
||||
private String payType;
|
||||
|
||||
private Long orderId;
|
||||
private Integer seatNum;
|
||||
/**
|
||||
* 用户端 使用 全打包 或者 全不打包
|
||||
*/
|
||||
private Integer userAllPack;
|
||||
|
||||
public boolean isAllPack() {
|
||||
return allPack != null && allPack == 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.czg.service.order.dto;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class UserCouponInfoDTO {
|
||||
private Long userCouponId;
|
||||
@Min(1)
|
||||
private Integer num;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.czg.service.order.mapper;
|
||||
|
||||
import com.czg.service.order.dto.MerchantQueryDTO;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.czg.order.entity.ShopDirectMerchant;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商户进件 映射层。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-07
|
||||
*/
|
||||
public interface ShopDirectMerchantMapper extends BaseMapper<ShopDirectMerchant> {
|
||||
|
||||
List<ShopDirectMerchant> getEntryList(@Param("queryParam") MerchantQueryDTO queryParam);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.czg.service.account.mapper;
|
||||
package com.czg.service.order.mapper;
|
||||
|
||||
import com.czg.account.entity.ShopMerchant;
|
||||
import com.czg.order.entity.ShopMerchant;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
/**
|
||||
@@ -1,17 +1,18 @@
|
||||
package com.czg.service.order.print;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.text.UnicodeUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.czg.account.dto.HandoverRecordDTO;
|
||||
import com.czg.account.entity.HandoverRecord;
|
||||
import com.czg.account.entity.PrintMachine;
|
||||
import com.czg.account.entity.ShopInfo;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.service.order.enums.OrderStatusEnums;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
@@ -20,24 +21,21 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
* 接口文档 <a href="https://help.feieyun.com/home/doc/zh;nav=1-1">
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Resource
|
||||
private ShopInfoService shopInfoService;
|
||||
|
||||
// API 地址
|
||||
private static final String URL = "http://api.feieyun.cn/Api/Open/";
|
||||
@@ -72,10 +70,8 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
String remark = orderDetail.getRemark();
|
||||
String content = buildDishPrintData(false, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
|
||||
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getNum(), remark, orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
|
||||
Object o = sendPrintRequest(machine.getAddress(), content, null, "1");
|
||||
printMachineLogService.save(machine, "新订单", content, o);
|
||||
|
||||
// printMachineLogService.save(machine, "新订单", , );
|
||||
String o = sendPrintRequest(machine.getAddress(), content, null, "1");
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "新订单", content, o);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,8 +80,8 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
String remark = orderDetail.getRemark();
|
||||
String content = buildDishPrintData(true, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
|
||||
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getReturnNum(), remark, orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
|
||||
Object o = sendPrintRequest(machine.getAddress(), content, null, "1");
|
||||
printMachineLogService.save(machine, "退款单", content, o);
|
||||
String o = sendPrintRequest(machine.getAddress(), content, null, "1");
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "退款单", content, o);
|
||||
|
||||
}
|
||||
|
||||
@@ -106,8 +102,8 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
.setRemark(orderInfo.getRemark())
|
||||
.setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
|
||||
String string = buildOrderPrintData(printInfoDTO, detailList);
|
||||
Object o = sendPrintRequest(machine.getAddress(), string, null, printerNum);
|
||||
printMachineLogService.save(machine, "退款单", string, o);
|
||||
String o = sendPrintRequest(machine.getAddress(), string, null, printerNum);
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "结算单", string, o);
|
||||
|
||||
}
|
||||
|
||||
@@ -134,24 +130,24 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
.setRemark(orderInfo.getRemark())
|
||||
.setDiscountAmount((orderInfo.getOriginAmount().add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee()).subtract(orderInfo.getPayAmount())).toPlainString());
|
||||
printInfoDTO.setPrintTitle(printInfoDTO.getPrintTitle());
|
||||
if(orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0){
|
||||
if (orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
printInfoDTO.setSeatNum(orderInfo.getSeatNum().toString());
|
||||
printInfoDTO.setSeatAmount(orderInfo.getSeatAmount().toPlainString());
|
||||
}
|
||||
if(orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0){
|
||||
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
|
||||
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
|
||||
}
|
||||
|
||||
String string = buildOrderPrintData(printInfoDTO, detailList);
|
||||
Object resp = sendPrintRequest(machine.getAddress(), string, null, printerNum);
|
||||
printMachineLogService.save(machine, "结算单", string, resp);
|
||||
String resp = sendPrintRequest(machine.getAddress(), string, null, printerNum);
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "结算单", string, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
|
||||
String data = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
|
||||
Object resp = sendPrintRequest(machine.getAddress(), data, voiceJson, "1");
|
||||
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, "1");
|
||||
printMachineLogService.save(machine, "叫号单", data, resp);
|
||||
}
|
||||
|
||||
@@ -170,7 +166,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
|
||||
public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
|
||||
log.info("飞蛾打印机开始发送打印请求, 设备地址: {}, 元数据: {}", address, metaPrintData);
|
||||
String time = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
@@ -189,12 +185,68 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
|
||||
|
||||
String result = restTemplate.postForObject(URL, requestEntity, String.class);
|
||||
log.info("打印结果: {}", result);
|
||||
return (R) result;
|
||||
log.info("飞鹅打印结果: {}", result);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("打印请求失败: {}", e.getMessage());
|
||||
throw new RuntimeException("飞蛾打印请求失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查飞鹅打印机 打印任务是否已打印
|
||||
*
|
||||
* @param printOrderId 打印订单编号
|
||||
* @return null-未知错误,true-已打印,false-未打印
|
||||
*/
|
||||
public Boolean checkFPrintStatus(String printOrderId) {
|
||||
String time = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("user", USER);
|
||||
paramMap.put("stime", time);
|
||||
paramMap.put("sig", signature(time));
|
||||
paramMap.put("apiname", "Open_queryOrderState");
|
||||
paramMap.put("orderid", printOrderId);
|
||||
Boolean ret;
|
||||
try {
|
||||
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
|
||||
//成功 {"msg":"ok","ret":0,"data":true,"serverExecutedTime":4}
|
||||
//失败 {"msg":"ok","ret":0,"data":false,"serverExecutedTime":4}
|
||||
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
|
||||
log.info("飞鹅打印机 打印任务状态响应: {}", json);
|
||||
ret = json.getBool("data");
|
||||
} catch (Exception e) {
|
||||
ret = null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查飞鹅打印机是否在线
|
||||
*
|
||||
* @param sn 设备编号
|
||||
* @return 在线,工作状态正常。/离线。/未知错误
|
||||
*/
|
||||
public String checkOnline(String sn) {
|
||||
String time = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("user", USER);
|
||||
paramMap.put("stime", time);
|
||||
paramMap.put("sig", signature(time));
|
||||
paramMap.put("apiname", "Open_queryPrinterStatus");
|
||||
paramMap.put("sn", sn);
|
||||
String msg;
|
||||
try {
|
||||
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
|
||||
//成功 开机 {"msg":"ok","ret":0,"data":"在线,工作状态正常。","serverExecutedTime":4}
|
||||
//成功 离线 {"msg":"ok","ret":0,"data":"离线。","serverExecutedTime":7}
|
||||
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
|
||||
log.info("飞鹅打印机状态响应: {}", json);
|
||||
msg = json.getStr("data");
|
||||
} catch (Exception e) {
|
||||
msg = "未知错误";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -49,10 +50,9 @@ public abstract class PrinterHandler {
|
||||
@Setter
|
||||
protected PrinterHandler nextPrinter;
|
||||
protected String printerBrand;
|
||||
// 创建 ThreadLocal 变量
|
||||
private static final ThreadLocal<String> ERR_MSG = ThreadLocal.withInitial(() -> "");
|
||||
|
||||
|
||||
@Resource
|
||||
protected RestTemplate restTemplate;
|
||||
@Resource
|
||||
protected OrderDetailService orderDetailService;
|
||||
@Resource
|
||||
@@ -84,7 +84,11 @@ public abstract class PrinterHandler {
|
||||
@Getter
|
||||
public enum PrintTypeEnum {
|
||||
HANDOVER("交班", "handover"),
|
||||
ORDER("订单", "order"), ONE("菜品", "one"), CALL("叫号", "call"), ONE_AND_ORDER("菜品和结算单同时打印", "oneAndOrder"), PRE_ORDER("预结算单", "preOrder");
|
||||
ORDER("订单", "order"),
|
||||
ONE("菜品", "one"),
|
||||
CALL("叫号", "call"),
|
||||
ONE_AND_ORDER("菜品和结算单同时打印", "oneAndOrder"),
|
||||
PRE_ORDER("预结算单", "preOrder");
|
||||
private final String name;
|
||||
private final String code;
|
||||
|
||||
@@ -157,7 +161,7 @@ public abstract class PrinterHandler {
|
||||
|
||||
if (StrUtil.isNotEmpty(printMethod)) {
|
||||
List<String> arrayList = switch (printMethod) {
|
||||
case "all" ->Arrays.asList("one", "normal", "all");
|
||||
case "all" -> Arrays.asList("one", "normal", "all");
|
||||
case "one" -> Arrays.asList("one", "all");
|
||||
case "normal" -> Arrays.asList("normal", "all");
|
||||
default -> new ArrayList<>();
|
||||
@@ -173,10 +177,6 @@ public abstract class PrinterHandler {
|
||||
wrapper.like(PrintMachine::getPrintType, printType);
|
||||
}
|
||||
List<PrintMachine> list = printMachineService.list(wrapper);
|
||||
// for (PrintMachine item : list) {
|
||||
// //实际打印以传递的参数为准
|
||||
// item.setPrintMethod(printMethod);
|
||||
// }
|
||||
if (list.isEmpty()) {
|
||||
log.error("店铺未配置打印机,店铺id: {}", shopId);
|
||||
return list;
|
||||
@@ -188,7 +188,8 @@ public abstract class PrinterHandler {
|
||||
|
||||
/**
|
||||
* 处理打印
|
||||
* @param data 传递的数据
|
||||
*
|
||||
* @param data 传递的数据
|
||||
* @param printTypeEnum order returnOrder preOrder one call handover
|
||||
*/
|
||||
public void handler(String data, PrintTypeEnum printTypeEnum) {
|
||||
@@ -314,7 +315,7 @@ public abstract class PrinterHandler {
|
||||
item.setNum(item.getNum().subtract(printDetailInfo.getPrintNum()));
|
||||
item.setReturnNum(item.getReturnNum().subtract(printDetailInfo.getPrintReturnNum()));
|
||||
orderDetails.add(item);
|
||||
}else {
|
||||
} else {
|
||||
orderDetails.add(item);
|
||||
}
|
||||
|
||||
@@ -334,34 +335,37 @@ public abstract class PrinterHandler {
|
||||
log.info("准备开始打印交班");
|
||||
if (data instanceof HandoverRecordDTO record) {
|
||||
handoverPrint(machine, record);
|
||||
}else {
|
||||
} else {
|
||||
throw new RuntimeException("传递数据类型有误");
|
||||
}
|
||||
break;
|
||||
case PrintTypeEnum.ORDER:
|
||||
log.info("准备开始打印订单");
|
||||
if (data instanceof OrderInfo orderInfo) {
|
||||
redisService.set("order:print:" + orderInfo.getId(),"", 180);
|
||||
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
|
||||
onlyFrontDesk(machine, false, orderInfo, orderDetailList);
|
||||
}else {
|
||||
} else {
|
||||
throw new RuntimeException("传递数据类型有误");
|
||||
}
|
||||
break;
|
||||
case PrintTypeEnum.PRE_ORDER:
|
||||
log.info("准备开始打印预结算订单");
|
||||
if (data instanceof OrderInfo orderInfo) {
|
||||
redisService.set("order:print:" + orderInfo.getId(),"", 180);
|
||||
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
|
||||
onlyFrontDesk(machine, true, orderInfo, orderDetailList);
|
||||
}else {
|
||||
} else {
|
||||
throw new RuntimeException("传递数据类型有误");
|
||||
}
|
||||
break;
|
||||
case PrintTypeEnum.ONE:
|
||||
log.info("准备开始打印菜品单");
|
||||
if (data instanceof OrderInfo orderInfo) {
|
||||
redisService.set("order:print:" + orderInfo.getId(),"", 180);
|
||||
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
|
||||
onlyKitchen(machine, orderInfo, orderDetailList);
|
||||
}else {
|
||||
} else {
|
||||
throw new RuntimeException("传递数据类型有误");
|
||||
}
|
||||
break;
|
||||
@@ -369,13 +373,14 @@ public abstract class PrinterHandler {
|
||||
log.info("准备开始打印叫号单");
|
||||
if (data instanceof CallQueue queue) {
|
||||
onlyCallNumPrint(machine, queue);
|
||||
}else {
|
||||
} else {
|
||||
throw new RuntimeException("传递数据类型有误");
|
||||
}
|
||||
break;
|
||||
case PrintTypeEnum.ONE_AND_ORDER:
|
||||
log.info("准备开始打印菜品以及结算单");
|
||||
if (data instanceof OrderInfo orderInfo) {
|
||||
redisService.set("order:print:" + orderInfo.getId(),"", 180);
|
||||
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
|
||||
switch (machine.getPrintMethod()) {
|
||||
case "all":
|
||||
@@ -393,7 +398,7 @@ public abstract class PrinterHandler {
|
||||
default:
|
||||
throw new RuntimeException("打印方法有误");
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
throw new RuntimeException("传递数据类型有误");
|
||||
}
|
||||
|
||||
@@ -448,17 +453,7 @@ public abstract class PrinterHandler {
|
||||
log.info("台位费商品,不打印");
|
||||
return;
|
||||
}
|
||||
// ProdSku sku = prodSkuService.getById(item.getSkuId());
|
||||
// if (isTemporary == 0 && sku == null) {
|
||||
// log.error("商品不存在, id: {}", item.getSkuId());
|
||||
// return;
|
||||
// } else if (isTemporary == 1) {
|
||||
// sku = new ProdSku();
|
||||
// }
|
||||
|
||||
|
||||
// String remark = StrUtil.isNotBlank(sku.getSpecInfo()) ? sku.getSpecInfo() : "";
|
||||
// item.setRemark(remark);
|
||||
if (item.getReturnNum().compareTo(BigDecimal.ZERO) > 0) {
|
||||
returnDishesPrint(orderInfo, item, machine);
|
||||
}
|
||||
@@ -469,8 +464,9 @@ public abstract class PrinterHandler {
|
||||
|
||||
// 保存已打印信息
|
||||
OrderDetail orderDetail = detailMap.get(item.getId());
|
||||
redisService.set(RedisCst.getPrintOrderDetailKey(orderInfo.getId(), item.getId()), JSONObject.toJSONString(new PrintDetailInfo().setPrint(item.getIsPrint() == 1).setDetailId(item.getId())
|
||||
.setPrintNum(orderDetail.getNum()).setPrintReturnNum(orderDetail.getReturnNum())), 3600 * 24);
|
||||
redisService.set(RedisCst.getPrintOrderDetailKey(orderInfo.getId(), item.getId()),
|
||||
JSONObject.toJSONString(new PrintDetailInfo().setPrint(item.getIsPrint() == 1).setDetailId(item.getId())
|
||||
.setPrintNum(orderDetail.getNum()).setPrintReturnNum(orderDetail.getReturnNum())), 3600 * 24);
|
||||
|
||||
});
|
||||
|
||||
@@ -582,17 +578,35 @@ public abstract class PrinterHandler {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 菜品打印
|
||||
*/
|
||||
protected abstract void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
|
||||
|
||||
/**
|
||||
* 菜品 退菜打印
|
||||
*/
|
||||
protected abstract void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
|
||||
|
||||
/**
|
||||
* 退单打印
|
||||
*/
|
||||
protected abstract void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList);
|
||||
|
||||
/**
|
||||
* 订单打印
|
||||
*/
|
||||
protected abstract void normalOrderPrint(OrderInfo orderInfo, boolean isPre, PrintMachine machine, String balance, List<OrderDetail> detailList);
|
||||
|
||||
/**
|
||||
* 叫号打印
|
||||
*/
|
||||
protected abstract void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum,
|
||||
String codeUrl, LocalDateTime takeTime, String shopNote);
|
||||
|
||||
/**
|
||||
* 交班打印
|
||||
*/
|
||||
protected abstract void handoverPrint(PrintMachine machine, HandoverRecordDTO record);
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.account.dto.HandoverRecordDTO;
|
||||
import com.czg.account.entity.HandoverRecord;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -69,10 +68,9 @@ public interface PrinterImpl {
|
||||
* @param metaPrintData 打印元数据
|
||||
* @param voiceData 语音信息
|
||||
* @param printNum 打印联数
|
||||
* @param <R> 返回数据类型
|
||||
* @return 打印结果
|
||||
*/
|
||||
<R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);
|
||||
String sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);
|
||||
|
||||
/**
|
||||
* 获取当前打印机标签信息
|
||||
@@ -560,12 +558,6 @@ public interface PrinterImpl {
|
||||
return str;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("水煮肉片".length());
|
||||
System.out.println(StrUtil.repeat(' ', 8));
|
||||
System.out.println(StrUtil.fillAfter("水煮肉片", ' ', 21));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取填充字符串, 并且换行
|
||||
*
|
||||
|
||||
@@ -4,11 +4,10 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.czg.account.dto.HandoverRecordDTO;
|
||||
import com.czg.account.entity.HandoverRecord;
|
||||
import com.czg.account.entity.PrintMachine;
|
||||
import com.czg.account.entity.ShopInfo;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.service.order.enums.OrderStatusEnums;
|
||||
@@ -20,16 +19,14 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 云享印打印机
|
||||
*
|
||||
* 博实结-云享印打印机
|
||||
* 接口文档 <a href="https://bsj2.yuque.com/bsj/izhmfn/rr8b5g?#ZbE6s">
|
||||
* @author Administrator
|
||||
*/
|
||||
@Slf4j
|
||||
@@ -45,12 +42,6 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
//APPSECRET
|
||||
private static final String APP_SECRET = "2022bsjZF544GAH";
|
||||
|
||||
@Resource
|
||||
private ShopInfoService shopInfoService;
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public YxyPrinter() {
|
||||
super("云想印");
|
||||
}
|
||||
@@ -75,7 +66,7 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
|
||||
|
||||
@Override
|
||||
public <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
|
||||
public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
|
||||
log.info("开始请求云享印,请求数据:{}, {}", voiceData, metaPrintData);
|
||||
//设备名称
|
||||
//行为方式 1:只打印数据 2:只播放信息 3:打印数据并播放信息
|
||||
@@ -87,10 +78,9 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
Map<String, String> param = getToken(time, uuid);
|
||||
//参数
|
||||
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
|
||||
multiValueMap.add("token", param.get("TOKEN"));
|
||||
multiValueMap.add("token", getToken(time, uuid));
|
||||
multiValueMap.add("devName", address);
|
||||
multiValueMap.add("actWay", 3);
|
||||
multiValueMap.add("cn", printNum);
|
||||
@@ -108,18 +98,17 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
httpEntity, String.class);
|
||||
|
||||
log.info("请求云享印成功,响应数据: {}", httpResponse);
|
||||
return (R) httpResponse;
|
||||
return httpResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
|
||||
String buildDishPrintData = buildDishPrintData(false, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
|
||||
orderDetail.getNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
Object resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
|
||||
// sendPrintRequest(voiceJson, 3, 1, machine.getAddress(), data);
|
||||
printMachineLogService.save(machine, "新订单", buildDishPrintData, resp);
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "新订单", buildDishPrintData, resp);
|
||||
|
||||
}
|
||||
|
||||
@@ -127,10 +116,9 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
protected void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
|
||||
String buildDishPrintData = buildDishPrintData(true, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
|
||||
orderDetail.getReturnNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
Object resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
|
||||
printMachineLogService.save(machine, "退款单", buildDishPrintData, resp);
|
||||
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "退款单", buildDishPrintData, resp);
|
||||
|
||||
}
|
||||
|
||||
@@ -138,21 +126,21 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
protected void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
|
||||
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName()).setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss")).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss"))
|
||||
.setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
|
||||
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("退款单")
|
||||
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
|
||||
|
||||
String data = buildOrderPrintData(printInfoDTO, detailList);
|
||||
String voiceJson = "{\"PbizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
String printerNum = "1";
|
||||
if (StrUtil.isNotBlank(machine.getPrintQty())) {
|
||||
printerNum = machine.getPrintQty().split("\\^")[1];
|
||||
}
|
||||
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
|
||||
printMachineLogService.save(machine, "新订单", data, resp);
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "退款单", data, resp);
|
||||
|
||||
}
|
||||
|
||||
@@ -165,7 +153,8 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
.le(OrderInfo::getCreateTime, orderInfo.getCreateTime()));
|
||||
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
|
||||
.setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss")).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss"))
|
||||
.setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOriginalAmount((orderInfo.getOriginAmount().add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())).toPlainString()).setReturn(isReturn(orderInfo))
|
||||
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle(isPre ? "预结算单" : "结算单")
|
||||
@@ -173,33 +162,38 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
.setRemark(orderInfo.getRemark())
|
||||
.setDiscountAmount((orderInfo.getOriginAmount().add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee()).subtract(orderInfo.getPayAmount())).toPlainString());
|
||||
printInfoDTO.setPrintTitle(printInfoDTO.getPrintTitle());
|
||||
if(orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0){
|
||||
if (orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
printInfoDTO.setSeatNum(orderInfo.getSeatNum().toString());
|
||||
printInfoDTO.setSeatAmount(orderInfo.getSeatAmount().toPlainString());
|
||||
}
|
||||
if(orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0){
|
||||
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
|
||||
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
|
||||
}
|
||||
|
||||
String data = buildOrderPrintData(printInfoDTO, detailList);
|
||||
String voiceJson = "{\"PbizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
String printerNum = "1";
|
||||
if (StrUtil.isNotBlank(machine.getPrintQty())) {
|
||||
printerNum = machine.getPrintQty().split("\\^")[1];
|
||||
}
|
||||
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
|
||||
// printMachineLogService.save(machine, printType, data, resp);
|
||||
printMachineLogService.save(machine, "新订单", data, resp);
|
||||
printMachineLogService.save(orderInfo.getId(), machine, "结算单", data, resp);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 叫号单打印
|
||||
*/
|
||||
@Override
|
||||
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
|
||||
String resp = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
|
||||
sendPrintRequest(machine.getAddress(), resp, null, "1");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 交班单打印
|
||||
*/
|
||||
@Override
|
||||
protected void handoverPrint(PrintMachine machine, HandoverRecordDTO record) {
|
||||
String string = buildHandoverData(record);
|
||||
@@ -214,9 +208,9 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
* @param requestId 请求ID,自定义
|
||||
* @return token信息
|
||||
*/
|
||||
private static Map<String, String> getToken(String timestamp, String requestId) {
|
||||
private static String getToken(String timestamp, String requestId) {
|
||||
StringBuilder token = new StringBuilder();
|
||||
StringBuilder encode = new StringBuilder();
|
||||
// StringBuilder encode = new StringBuilder();
|
||||
SortedMap<String, Object> map = new TreeMap<>();
|
||||
map.put("appId", APP_ID);
|
||||
map.put("timestamp", timestamp);
|
||||
@@ -226,13 +220,38 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
String key = next.getKey();
|
||||
Object value = next.getValue();
|
||||
token.append(key).append(value);
|
||||
encode.append(key).append("=").append(value).append("&");
|
||||
// encode.append(key).append("=").append(value).append("&");
|
||||
}
|
||||
Map<String, String> finalMap = new HashMap<>();
|
||||
finalMap.put("ENCODE", encode.toString());
|
||||
finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
|
||||
return finalMap;
|
||||
// Map<String, String> finalMap = new HashMap<>();
|
||||
// finalMap.put("ENCODE", encode.toString());
|
||||
// finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
|
||||
// return finalMap;
|
||||
return SecureUtil.md5(token + APP_SECRET).toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查打印状态
|
||||
*
|
||||
* @param devName 设备名称,(唯一) 对应配置表中的address字段即(IP地址/打印机编号)
|
||||
* @param taskId 打印任务id,用于复查打印状态,云想印=orderId
|
||||
*/
|
||||
public String checkPrintStatus(String devName, String taskId) {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
|
||||
paramMap.put("devName", devName);
|
||||
paramMap.put("orderId", taskId);
|
||||
paramMap.put("token", getToken(time, uuid));
|
||||
paramMap.put("appId", APP_ID);
|
||||
paramMap.put("timestamp", time);
|
||||
paramMap.put("requestId", uuid);
|
||||
paramMap.put("userCode", USER_CODE);
|
||||
String s = HttpUtil.get("https://ioe.car900.com/v1/openApi/dev/findOrder.json", paramMap, 1000 * 5);
|
||||
log.info("云想印打印机:{},任务:{}状态:{}", devName, taskId, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,33 +7,20 @@ import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* 支付
|
||||
* 分销员支付
|
||||
*
|
||||
* @author ww
|
||||
*/
|
||||
public interface DistributionPayService {
|
||||
/**
|
||||
* 现金支付
|
||||
*/
|
||||
CzgResult<Object> cashPayOrder(MkDistributionPayDTO payParam);
|
||||
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> ltPayOrder(String clintIp, MkDistributionPayDTO payParam);
|
||||
|
||||
/**
|
||||
* PC扫码支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> scanPayOrder(String clintIp, MkDistributionPayDTO payParam);
|
||||
|
||||
/**
|
||||
* 反扫
|
||||
* 运营端小程序余额充值
|
||||
*/
|
||||
CzgResult<Map<String, Object>> microPayOrder(MkDistributionPayDTO payParam);
|
||||
|
||||
|
||||
Map<String, String> mchRecharge(String clientIP, MkDistributionPayDTO payParam);
|
||||
Map<String, String> mchRecharge(MkDistributionPayDTO payParam);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.czg.service.order.service;
|
||||
|
||||
import com.czg.order.dto.OrderInfoRefundDTO;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.order.dto.OrderPayParamDTO;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
*/
|
||||
public interface OrderPayService {
|
||||
|
||||
/**
|
||||
* 挂账
|
||||
*/
|
||||
CzgResult<Object> creditPayOrder(OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 现金支付
|
||||
*/
|
||||
CzgResult<Object> cashPayOrder(OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 余额支付
|
||||
*/
|
||||
CzgResult<Object> vipPayOrder(OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* h5支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> h5PayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* js支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> jsPayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 空订单支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> js2PayOrder(@NonNull String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> ltPayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* PC扫码支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> scanPayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 聚合反扫
|
||||
*/
|
||||
CzgResult<Map<String, Object>> microPayOrder(OrderPayParamDTO payParam);
|
||||
//-----------------------------------------------------------------订单+会员 一起支付-----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 充值并付款
|
||||
*/
|
||||
CzgResult<Map<String, Object>> rechargePayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------退款-----------------------------------------------------------------
|
||||
|
||||
//订单退款
|
||||
CzgResult<Object> refundOrderBefore(OrderInfoRefundDTO param);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.czg.service.order.service;
|
||||
|
||||
import com.czg.entity.resp.CzgBaseResp;
|
||||
import com.czg.entity.resp.CzgRefundResp;
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.order.dto.LtPayOtherDTO;
|
||||
import com.czg.order.dto.OrderInfoRefundDTO;
|
||||
import com.czg.order.entity.OrderPayment;
|
||||
import com.czg.pay.CzgPayBaseReq;
|
||||
import com.czg.pay.CzgRefundReq;
|
||||
import com.czg.pay.QueryOrderRespDTO;
|
||||
import com.czg.pay.RefundRespDTO;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.order.dto.OrderPayParamDTO;
|
||||
import com.czg.service.order.dto.VipMemberPayParamDTO;
|
||||
import com.czg.service.order.dto.VipPayParamDTO;
|
||||
import com.czg.service.order.dto.VipRefundDTO;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -22,129 +20,41 @@ import java.util.Map;
|
||||
* @author ww
|
||||
*/
|
||||
public interface PayService {
|
||||
//-----------------------------------------------------------------订单支付--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 挂账
|
||||
*/
|
||||
CzgResult<Object> creditPayOrder(OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 现金支付
|
||||
*/
|
||||
CzgResult<Object> cashPayOrder(OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 余额支付
|
||||
*/
|
||||
CzgResult<Object> vipPayOrder(OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* h5支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> h5PayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* js支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> jsPayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 空订单支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> js2PayOrder(@NonNull String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> ltPayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* PC扫码支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> scanPayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 聚合反扫
|
||||
*/
|
||||
CzgResult<Map<String, Object>> microPayOrder(OrderPayParamDTO payParam);
|
||||
//-----------------------------------------------------------------订单+会员 一起支付-----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 充值并付款
|
||||
*/
|
||||
CzgResult<Map<String, Object>> rechargePayOrder(String clintIp, OrderPayParamDTO payParam);
|
||||
//-----------------------------------------------------------------会员支付--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 现金充值
|
||||
*/
|
||||
CzgResult<Object> cashPayVip(VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* js支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> jsPayVip(String clintIp, VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> ltPayVip(String clintIp, VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* PC扫码支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> scanPayVip(String clintIp, VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 聚合反扫
|
||||
*/
|
||||
CzgResult<Map<String, Object>> microPayVip(VipPayParamDTO payParam);
|
||||
//-----------------------------------------------------------------会员开通购买 ----------------------------------------------------------
|
||||
|
||||
CzgResult<Map<String, Object>> ltPayMember(String clientIP, VipMemberPayParamDTO payParam);
|
||||
|
||||
CzgResult<Map<String, Object>> recharge(String clientIP, VipPayParamDTO rechargeDTO, Long userId);
|
||||
BigDecimal MONEY_RATE = new BigDecimal("100");
|
||||
|
||||
|
||||
Long initPayment(OrderPayment payment);
|
||||
|
||||
//-----------------------------------------------------------------付款 ----------------------------------------------------------
|
||||
CzgResult<Map<String, Object>> pay(@NonNull Long shopId, CzgPayEnum payType, CzgPayBaseReq bizData);
|
||||
//-----------------------------------------------------------------积分商品/拼团 付款 ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @param param 支付参数
|
||||
* @param payType 暂时只有 POINT 积分 和 WARE 拼团商品
|
||||
* @param payType {@link com.czg.constants.PayTypeConstants.SourceType} 常量
|
||||
* @param detail 操作描述 如 积分商品购买 / 拼团商品购买
|
||||
*/
|
||||
CzgResult<Map<String, Object>> ltPayOther(LtPayOtherDTO param, String payType, String detail);
|
||||
|
||||
//-----------------------------------------------------------------退款-----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 退款前校验
|
||||
*/
|
||||
CzgResult<Map<String, BigDecimal>> refundVipBefore(VipRefundDTO payParam);
|
||||
|
||||
/**
|
||||
* 会员退款
|
||||
* 退款
|
||||
* 目前订单 会员 使用
|
||||
*/
|
||||
CzgResult<Object> refundVip(VipRefundDTO payParam);
|
||||
|
||||
CzgResult<Object> refundOrderBefore(OrderInfoRefundDTO param);
|
||||
|
||||
/**
|
||||
* 订单退款
|
||||
*/
|
||||
void refundOrder(Long shopId, Long orderId, Long payOrderId, String refPayOrderNo, String refundReason, BigDecimal refundAmount);
|
||||
|
||||
CzgResult<RefundRespDTO> refund(@NonNull Long shopId, CzgRefundReq bizData);
|
||||
/**
|
||||
* 统一退款接口
|
||||
*
|
||||
* 目前 拼团商品 积分商品 套餐推广 使用
|
||||
* @param refPayOrderNo 自定义退单号 {@link com.czg.enums.OrderNoPrefixEnum} + 雪花Id
|
||||
*/
|
||||
void unifyRefund(Long shopId, Long sourceId, Long payOrderId, String refPayOrderNo, String refundReason, BigDecimal refundAmount);
|
||||
|
||||
/**
|
||||
* 退款补偿使用
|
||||
* 目前 拼团商品 积分商品 套餐推广 使用
|
||||
* (退款 账户余额不足时 会失败定时任务)
|
||||
*/
|
||||
void unifyRefund(OrderPayment payment, String refPayOrderNo);
|
||||
|
||||
@@ -157,7 +67,7 @@ public interface PayService {
|
||||
* @param payOrderId 平台订单号
|
||||
* @param mchOrderNo 商户订单号
|
||||
*/
|
||||
CzgResult<CzgBaseResp> queryPayOrder(Long shopId, String payOrderId, String mchOrderNo);
|
||||
CzgResult<QueryOrderRespDTO> queryPayOrder(Long shopId, String payOrderId, String mchOrderNo, String platform);
|
||||
|
||||
/**
|
||||
* 退款查询
|
||||
@@ -165,5 +75,5 @@ public interface PayService {
|
||||
* @param mchRefundNo 商户退款订单号 二选一
|
||||
* @param refundOrderId 平台退款订单号 二选一
|
||||
*/
|
||||
CzgResult<CzgRefundResp> queryRefund(Long shopId, String mchRefundNo, String refundOrderId);
|
||||
CzgResult<RefundRespDTO> queryRefund(Long shopId, String mchRefundNo, String refundOrderId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.czg.service.order.service;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.dto.req.AggregateMerchantDto;
|
||||
import com.czg.service.order.dto.AggregateMerchantVO;
|
||||
import com.czg.service.order.dto.MerchantQueryDTO;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.service.IService;
|
||||
import com.czg.order.entity.ShopDirectMerchant;
|
||||
|
||||
/**
|
||||
* 商户进件 服务层。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-07
|
||||
*/
|
||||
public interface ShopDirectMerchantService extends IService<ShopDirectMerchant> {
|
||||
|
||||
/**
|
||||
* ocr识别图片
|
||||
* @param url 图片地址
|
||||
* @param type IdCard 身份证
|
||||
* BankCard 银行卡
|
||||
* BusinessLicense 营业执照
|
||||
*/
|
||||
JSONObject getInfoByImg(String url, String type) throws Exception;
|
||||
|
||||
|
||||
Page<ShopDirectMerchant> getEntryList(MerchantQueryDTO queryParam);
|
||||
/**
|
||||
* 获取进件信息
|
||||
*/
|
||||
AggregateMerchantVO getEntry(Long shopId);
|
||||
|
||||
/**
|
||||
* 申请进件
|
||||
*/
|
||||
boolean entryManager(AggregateMerchantDto reqDto);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.czg.service.order.service;
|
||||
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.order.dto.VipMemberPayParamDTO;
|
||||
import com.czg.service.order.dto.VipPayParamDTO;
|
||||
import com.czg.service.order.dto.VipRefundDTO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* 用户余额 充值/会员购买开通
|
||||
* @author ww
|
||||
*/
|
||||
public interface ShopUserPayService {
|
||||
|
||||
//-----------------------------------------------------------------会员支付--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 现金充值
|
||||
*/
|
||||
CzgResult<Object> cashPayVip(VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* js支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> jsPayVip(String clintIp, VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> ltPayVip(String clintIp, VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* PC扫码支付
|
||||
*/
|
||||
CzgResult<Map<String, Object>> scanPayVip(String clintIp, VipPayParamDTO payParam);
|
||||
|
||||
/**
|
||||
* 聚合反扫
|
||||
*/
|
||||
CzgResult<Map<String, Object>> microPayVip(VipPayParamDTO payParam);
|
||||
//-----------------------------------------------------------------会员开通购买 ----------------------------------------------------------
|
||||
|
||||
CzgResult<Map<String, Object>> ltPayMember(String clientIP, VipMemberPayParamDTO payParam);
|
||||
|
||||
CzgResult<Map<String, Object>> recharge(String clientIP, VipPayParamDTO rechargeDTO, Long userId);
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------退款-----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 退款前校验
|
||||
*/
|
||||
CzgResult<Map<String, BigDecimal>> refundVipBefore(VipRefundDTO payParam);
|
||||
|
||||
/**
|
||||
* 会员退款
|
||||
*/
|
||||
CzgResult<Object> refundVip(VipRefundDTO payParam);
|
||||
}
|
||||
@@ -3,18 +3,19 @@ package com.czg.service.order.service.impl;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.czg.account.entity.ShopUser;
|
||||
import com.czg.account.entity.UserInfo;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.account.service.ShopUserService;
|
||||
import com.czg.account.service.UserInfoService;
|
||||
import com.czg.constant.TableValueConstant;
|
||||
import com.czg.entity.req.CzgLtPayReq;
|
||||
import com.czg.constants.PayTypeConstants;
|
||||
import com.czg.constants.SystemConstants;
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.market.service.MkDistributionConfigService;
|
||||
import com.czg.market.vo.MkDistributionConfigVO;
|
||||
import com.czg.order.dto.MkDistributionPayDTO;
|
||||
import com.czg.order.entity.OrderPayment;
|
||||
import com.czg.constants.PayTypeConstants;
|
||||
import com.czg.order.service.OrderPaymentService;
|
||||
import com.czg.pay.CzgPayBaseReq;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.market.service.impl.WxServiceImpl;
|
||||
import com.czg.service.order.service.DistributionPayService;
|
||||
@@ -44,8 +45,6 @@ public class DistributionPayServiceImpl implements DistributionPayService {
|
||||
@Resource
|
||||
private PayServiceImpl payService;
|
||||
|
||||
@DubboReference
|
||||
private ShopInfoService shopInfoService;
|
||||
@DubboReference
|
||||
private ShopUserService shopUserService;
|
||||
@DubboReference
|
||||
@@ -70,7 +69,7 @@ public class DistributionPayServiceImpl implements DistributionPayService {
|
||||
ShopUser shopUserInfo = shopUserService.getShopUserInfo(payParam.getShopId(), userId);
|
||||
|
||||
OrderPayment orderPayment = new OrderPayment().setShopId(payParam.getShopId()).setSourceId(isRecharge ? payParam.getShopId() : shopUserInfo.getId())
|
||||
.setSourceType(isRecharge ? PayTypeConstants.SourceType.DISTRIBUTION_RECHARGE : PayTypeConstants.SourceType.DISTRIBUTION )
|
||||
.setSourceType(isRecharge ? PayTypeConstants.SourceType.DISTRIBUTION_RECHARGE : PayTypeConstants.SourceType.DISTRIBUTION)
|
||||
.setPayType(PayTypeConstants.PayType.PAY)
|
||||
.setOrderNo(payParam.getPlatformType() + IdUtil.getSnowflakeNextId())
|
||||
.setAmount(isRecharge ? payParam.getAmount() : detail.getPayAmount());
|
||||
@@ -84,36 +83,22 @@ public class DistributionPayServiceImpl implements DistributionPayService {
|
||||
} else {
|
||||
UserInfo userInfo = userInfoService.getById(userId);
|
||||
initInfo.setPayment(orderPayment).setShopUser(shopUserInfo)
|
||||
.setOpenId("aliPay".equals(payParam.getPayType()) ? userInfo.getAlipayOpenId() : userInfo.getWechatOpenId());
|
||||
.setOpenId(SystemConstants.PayType.ALIPAY.equals(payParam.getPayType()) ? userInfo.getAlipayOpenId() : userInfo.getWechatOpenId());
|
||||
}
|
||||
return initInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Object> cashPayOrder(MkDistributionPayDTO payParam) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> ltPayOrder(String clintIp, MkDistributionPayDTO payParam) {
|
||||
InitInfo initInfo = initPayment(payParam.getUserId(), payParam, false);
|
||||
return payService.ltPay(payParam.getShopId(), payParam.getPayType(), new CzgLtPayReq(initInfo.payment.getOrderNo(), initInfo.payment.getAmount().multiply(MONEY_RATE).longValue(),
|
||||
payParam.getPayType(), "分销员开通", initInfo.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.LT_PAY,
|
||||
CzgPayBaseReq.ltPayReq(initInfo.payment.getOrderNo(), "分销员开通", initInfo.payment.getAmount().multiply(MONEY_RATE).longValue(),
|
||||
payParam.getPayType(), initInfo.getOpenId(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> mchRecharge(String clientIP, MkDistributionPayDTO payParam) {
|
||||
public Map<String, String> mchRecharge(MkDistributionPayDTO payParam) {
|
||||
InitInfo initInfo = initPayment(payParam.getUserId() == null ? payParam.getShopId() : payParam.getUserId(), payParam, true);
|
||||
return wxService.v3Pay(initInfo.openId, payParam.getAmount(), "商户运营余额充值", initInfo.payment.getOrderNo(), initInfo.payment.getSourceType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> scanPayOrder(String clintIp, MkDistributionPayDTO payParam) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> microPayOrder(MkDistributionPayDTO payParam) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.exceptions.ValidateException;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
@@ -17,9 +20,8 @@ import com.czg.config.RabbitPublisher;
|
||||
import com.czg.config.RedisCst;
|
||||
import com.czg.constant.MarketConstants;
|
||||
import com.czg.constant.TableValueConstant;
|
||||
import com.czg.entity.notify.CzgPayNotifyDTO;
|
||||
import com.czg.entity.notify.CzgRefundNotifyDTO;
|
||||
import com.czg.constants.PayTypeConstants;
|
||||
import com.czg.entity.notify.CzgRefundNotifyDTO;
|
||||
import com.czg.enums.ShopTableStatusEnum;
|
||||
import com.czg.enums.ShopUserFlowBizEnum;
|
||||
import com.czg.exception.CzgException;
|
||||
@@ -40,6 +42,7 @@ import com.czg.order.entity.OrderPayment;
|
||||
import com.czg.order.enums.PayEnums;
|
||||
import com.czg.order.service.*;
|
||||
import com.czg.order.vo.*;
|
||||
import com.czg.pay.PayNotifyRespDTO;
|
||||
import com.czg.product.entity.Product;
|
||||
import com.czg.product.service.ProductRpcService;
|
||||
import com.czg.product.service.ProductService;
|
||||
@@ -50,7 +53,6 @@ import com.czg.service.order.enums.OrderStatusEnums;
|
||||
import com.czg.service.order.mapper.OrderInfoCustomMapper;
|
||||
import com.czg.service.order.print.PrinterHandler;
|
||||
import com.czg.utils.*;
|
||||
import com.czg.utils.PageUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -299,6 +301,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
orderDetails.forEach(item -> {
|
||||
item.setUrgent(true);
|
||||
item.setSubStatus(TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE.getCode());
|
||||
item.setStartOrderTime(DateUtil.date().toLocalDateTime());
|
||||
});
|
||||
} else {
|
||||
switch (EnumUtil.fromString(TableValueConstant.OrderDetail.SubStatus.class, param.getSubStatus())) {
|
||||
@@ -1027,13 +1030,12 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void payCallBackOrder(@NotBlank String orderNo, @NotNull JSONObject resultJson, int retryCount) {
|
||||
CzgPayNotifyDTO czgCallBackDto = JSONObject.parseObject(resultJson.toString(), CzgPayNotifyDTO.class);
|
||||
public void payCallBackOrder(@NotBlank String orderNo, @NotNull PayNotifyRespDTO notifyRespDTO, String channel, int retryCount) {
|
||||
OrderPayment payment = paymentService.getOne(new QueryWrapper().eq(OrderPayment::getOrderNo, orderNo));
|
||||
if (payment == null) {
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
log.info("支付记录不存在,第 {} 次重试,将在 {} 秒后进行", retryCount + 1, DELAY);
|
||||
executorService.schedule(() -> payCallBackOrder(orderNo, resultJson, retryCount + 1), DELAY, TimeUnit.SECONDS);
|
||||
executorService.schedule(() -> payCallBackOrder(orderNo, notifyRespDTO, channel, retryCount + 1), DELAY, TimeUnit.SECONDS);
|
||||
} else {
|
||||
log.error("订单支付回调失败, 达到最大重试次数, 支付记录不存在, orderNo: {}", orderNo);
|
||||
}
|
||||
@@ -1043,10 +1045,12 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
log.info("订单处理过,payment id:{}", payment.getId());
|
||||
return;
|
||||
}
|
||||
payment.setTradeNumber(czgCallBackDto.getPayOrderId());
|
||||
payment.setRespJson(resultJson.toString());
|
||||
payment.setTradeNumber(notifyRespDTO.getThirdOrderNo());
|
||||
payment.setRespJson(notifyRespDTO.getOriginalData());
|
||||
payment.setPayStatus(PayTypeConstants.PayStatus.FAIL);
|
||||
if ("TRADE_SUCCESS".equals(czgCallBackDto.getState())) {
|
||||
payment.setPlatformType(notifyRespDTO.getPlatform());
|
||||
payment.setChannel(channel);
|
||||
if ("TRADE_SUCCESS".equals(notifyRespDTO.getStatus())) {
|
||||
payment.setPayStatus(PayTypeConstants.PayStatus.SUCCESS);
|
||||
if (PayTypeConstants.SourceType.ORDER.equals(payment.getSourceType())) {
|
||||
OrderInfo orderInfo = orderInfoService.getById(payment.getSourceId());
|
||||
@@ -1054,8 +1058,8 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
log.error("订单支付回调失败,订单不存在,支付记录Id,{}", payment.getId());
|
||||
return;
|
||||
}
|
||||
upOrderInfo(orderInfo, new BigDecimal(czgCallBackDto.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.DOWN),
|
||||
DateUtil.parseLocalDateTime(czgCallBackDto.getPayTime()), payment.getId(), null);
|
||||
upOrderInfo(orderInfo, new BigDecimal(notifyRespDTO.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.DOWN),
|
||||
DateUtil.parseLocalDateTime(notifyRespDTO.getPaySuccessTime()), payment.getId(), null);
|
||||
if (orderInfo.getUserId() != null) {
|
||||
// 分销员升级等级
|
||||
distributionUserService.costUpgradeLevelBefore(orderInfo.getUserId(), orderInfo.getShopId());
|
||||
@@ -1065,14 +1069,14 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
} else if (PayTypeConstants.SourceType.MEMBER_IN.equals(payment.getSourceType()) || PayTypeConstants.SourceType.FREE.equals(payment.getSourceType())) {
|
||||
boolean isFree = PayTypeConstants.SourceType.FREE.equals(payment.getSourceType());
|
||||
ShopUser shopUser = shopUserService.getById(payment.getSourceId());
|
||||
OrderInfo orderInfo = null;
|
||||
OrderInfo orderInfo;
|
||||
if (shopUser == null) {
|
||||
log.error("会员充值失败,会员不存在,会员id:{}", payment.getSourceId());
|
||||
} else {
|
||||
ShopUserFlowBizEnum bizEnum;
|
||||
if ("WECHAT".equals(czgCallBackDto.getPayType())) {
|
||||
if ("WECHAT".equals(notifyRespDTO.getPlatform())) {
|
||||
bizEnum = ShopUserFlowBizEnum.WECHAT_IN;
|
||||
} else if ("ALIPAY".equals(czgCallBackDto.getPayType())) {
|
||||
} else if ("ALIPAY".equals(notifyRespDTO.getPlatform())) {
|
||||
bizEnum = ShopUserFlowBizEnum.ALIPAY_IN;
|
||||
} else {
|
||||
bizEnum = ShopUserFlowBizEnum.CASH_IN;
|
||||
@@ -1088,7 +1092,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
.setType(1)
|
||||
.setBizEnum(ShopUserFlowBizEnum.FREE_IN)
|
||||
.setRelationId(orderInfo.getId())
|
||||
.setMoney(BigDecimal.valueOf(czgCallBackDto.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
|
||||
.setMoney(BigDecimal.valueOf(notifyRespDTO.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
|
||||
shopUserService.updateMoney(shopUserMoneyEditDTO);
|
||||
upOrderInfo(orderInfo, BigDecimal.ZERO,
|
||||
LocalDateTime.now(), null, PayEnums.FREE_PAY);
|
||||
@@ -1110,26 +1114,21 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
|
||||
LocalDateTime.now(), null, PayEnums.VIP_PAY);
|
||||
}
|
||||
shopRechargeService.recharge(payment.getShopId(), payment.getSourceId(), payment.getRelatedId(),
|
||||
BigDecimal.valueOf(czgCallBackDto.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN),
|
||||
BigDecimal.valueOf(notifyRespDTO.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN),
|
||||
payment.getId(), payment.getSourceType(), bizEnum, orderInfo == null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
|
||||
} else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
|
||||
//购买会员
|
||||
ShopUser shopUser = shopUserService.getById(payment.getSourceId());
|
||||
memberConfigService.joinMember(payment.getShopId(), shopUser.getUserId(), payment.getRelatedId());
|
||||
}
|
||||
else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
|
||||
} else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
|
||||
distributionUserService.open(payment.getSourceId(), payment.getAmount(), payment.getShopId(), payment.getId());
|
||||
}
|
||||
else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
|
||||
} else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
|
||||
goodPayService.payCallBack(payment.getSourceId(), payment.getId());
|
||||
}
|
||||
else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
|
||||
} else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
|
||||
gbOrderService.payCallBack(payment.getSourceId(), payment.getId());
|
||||
}
|
||||
else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
|
||||
} else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
|
||||
ppPackageOrderService.paySuccess(payment.getSourceId(), payment.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,567 @@
|
||||
package com.czg.service.order.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
|
||||
import com.czg.account.entity.ShopInfo;
|
||||
import com.czg.account.entity.ShopUser;
|
||||
import com.czg.account.entity.UserInfo;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.account.service.ShopUserService;
|
||||
import com.czg.account.service.UserInfoService;
|
||||
import com.czg.config.RabbitPublisher;
|
||||
import com.czg.config.RedisCst;
|
||||
import com.czg.constants.PayTypeConstants;
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.enums.ShopUserFlowBizEnum;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.exception.PaySuccessException;
|
||||
import com.czg.market.entity.MkShopRechargeDetail;
|
||||
import com.czg.market.enums.PointsConstant;
|
||||
import com.czg.market.service.*;
|
||||
import com.czg.market.vo.MkShopRechargeVO;
|
||||
import com.czg.order.dto.CheckOrderPay;
|
||||
import com.czg.order.dto.OrderInfoRefundDTO;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.order.entity.OrderPayment;
|
||||
import com.czg.order.enums.PayEnums;
|
||||
import com.czg.order.service.CreditBuyerOrderService;
|
||||
import com.czg.order.service.OrderDetailService;
|
||||
import com.czg.order.service.OrderInfoCustomService;
|
||||
import com.czg.order.service.OrderPaymentService;
|
||||
import com.czg.pay.CzgPayBaseReq;
|
||||
import com.czg.pay.CzgRefundReq;
|
||||
import com.czg.pay.RefundRespDTO;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.RedisService;
|
||||
import com.czg.service.order.dto.OrderPayParamDTO;
|
||||
import com.czg.service.order.enums.OrderStatusEnums;
|
||||
import com.czg.service.order.service.OrderPayService;
|
||||
import com.czg.service.order.service.PayService;
|
||||
import com.czg.utils.AssertUtil;
|
||||
import com.czg.utils.CzgRandomUtils;
|
||||
import com.czg.utils.FunUtils;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OrderPayServiceImpl implements OrderPayService {
|
||||
@Resource
|
||||
private PayService payService;
|
||||
@Resource
|
||||
private OrderPaymentService paymentService;
|
||||
@DubboReference
|
||||
private ShopUserService shopUserService;
|
||||
@DubboReference
|
||||
private UserInfoService userInfoService;
|
||||
@DubboReference
|
||||
private ShopInfoService shopInfoService;
|
||||
@Resource
|
||||
private OrderInfoCustomService orderInfoCustomService;
|
||||
@Resource
|
||||
private OrderInfoService orderInfoService;
|
||||
@Resource
|
||||
private CreditBuyerOrderService buyerOrderService;
|
||||
@Resource
|
||||
private RedisService redisService;
|
||||
@Resource
|
||||
private RabbitPublisher rabbitPublisher;
|
||||
@Resource
|
||||
private MkShopRechargeService shopRechargeService;
|
||||
@Resource
|
||||
private MkShopRechargeDetailService shopRechargeDetailService;
|
||||
@Resource
|
||||
private OrderDetailService orderDetailService;
|
||||
@Resource
|
||||
private MkDistributionUserService distributionUserService;
|
||||
@Resource
|
||||
private MkShopConsumerCouponService consumerCouponService;
|
||||
@Resource
|
||||
private MkPointsUserService mkPointsUserService;
|
||||
@Resource
|
||||
private MkConsumeCashbackService consumeCashbackService;
|
||||
@Resource
|
||||
private MkPointsConfigService pointsConfigService;
|
||||
|
||||
private OrderInfo checkPay(CheckOrderPay checkOrderPay) {
|
||||
OrderInfo orderInfo = orderInfoCustomService.checkOrderPay(checkOrderPay);
|
||||
if (orderInfo.getOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
|
||||
//发送打票信息
|
||||
//orderId_0_0 订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成
|
||||
//orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_0"
|
||||
rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1", orderInfo.getIsPrint() == 1);
|
||||
redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
|
||||
throw new PaySuccessException("支付成功");
|
||||
}
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Object> creditPayOrder(OrderPayParamDTO payParam) {
|
||||
AssertUtil.isNull(payParam.getCreditBuyerId(), "请选择挂账人后支付");
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
orderInfo.setCreditBuyerId(payParam.getCreditBuyerId());
|
||||
orderInfoCustomService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
|
||||
LocalDateTime.now(), null, PayEnums.CREDIT_PAY);
|
||||
//挂账后续逻辑
|
||||
buyerOrderService.save(payParam.getCreditBuyerId().toString(), orderInfo.getId());
|
||||
return CzgResult.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Object> cashPayOrder(OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
orderInfoCustomService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
|
||||
LocalDateTime.now(), null, PayEnums.CASH_PAY);
|
||||
return CzgResult.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Object> vipPayOrder(OrderPayParamDTO payParam) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
|
||||
AssertUtil.isNull(shopInfo, "店铺不存在");
|
||||
if (!shopInfo.getIsAccountPay().equals(1)) {
|
||||
return CzgResult.failure("支付失败,店铺暂未开启会员余额支付。");
|
||||
}
|
||||
ShopUser shopUser = new ShopUser();
|
||||
if ("scanCode".equals(payParam.getPayType())) {
|
||||
AssertUtil.isBlank(payParam.getAuthCode(), "会员码不能为空");
|
||||
Object o = redisService.get(RedisCst.SHOP_USER_DYNAMIC_CODE + payParam.getShopId() + ":" + payParam.getAuthCode());
|
||||
AssertUtil.isNull(o, "会员码已失效");
|
||||
shopUser = shopUserService.getById(o.toString());
|
||||
} else {
|
||||
if ("userPay".equals(payParam.getPayType())) {
|
||||
AssertUtil.isNull(payParam.getShopUserId(), "请选择付款人后重试");
|
||||
shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
} else if ("accountPay".equals(payParam.getPayType())) {
|
||||
shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "会员不存在");
|
||||
UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
|
||||
AssertUtil.isNull(userInfo, "用户信息不存在");
|
||||
if (userInfo.getUsePayPwd() == 1) {
|
||||
AssertUtil.isBlank(payParam.getPwd(), "支付密码不能为空");
|
||||
if (userInfo.getPayPwd() == null || !userInfo.getPayPwd().equals(MD5.create().digestHex((payParam.getPwd())))) {
|
||||
return CzgResult.failure("支付密码错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shopUser == null || shopUser.getId() == null) {
|
||||
AssertUtil.isNull(shopUser, "会员不存在");
|
||||
}
|
||||
payParam.getCheckOrderPay().setUserId(shopUser.getUserId());
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
if (shopInfo.getIsHeadShop().equals(1)) {
|
||||
if (!shopUser.getMainShopId().equals(orderInfo.getShopId())) {
|
||||
return CzgResult.failure("违规操作,请确认店铺后重试");
|
||||
}
|
||||
} else {
|
||||
boolean exists = shopInfoService.exists(QueryWrapper.create()
|
||||
.eq(ShopInfo::getMainId, shopInfo.getMainId())
|
||||
.eq(ShopInfo::getId, orderInfo.getShopId()));
|
||||
if (!exists) {
|
||||
return CzgResult.failure("违规操作,请确认店铺后重试");
|
||||
}
|
||||
}
|
||||
if (shopUser.getAmount().compareTo(orderInfo.getOrderAmount()) < 0) {
|
||||
return CzgResult.failure("会员余额不足");
|
||||
}
|
||||
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
|
||||
.setId(shopUser.getId())
|
||||
.setMoney(orderInfo.getOrderAmount())
|
||||
.setType(0)
|
||||
.setBizEnum(ShopUserFlowBizEnum.ORDER_PAY)
|
||||
.setRelationId(orderInfo.getId());
|
||||
//更新会员余额 并生成流水
|
||||
if (payParam.getCheckOrderPay() != null && StrUtil.isNotBlank(payParam.getCheckOrderPay().getRemark())) {
|
||||
orderInfo.setRemark(payParam.getCheckOrderPay().getRemark());
|
||||
}
|
||||
|
||||
Long flowId = shopUserService.updateMoney(shopUserMoneyEditDTO);
|
||||
orderInfoCustomService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
|
||||
LocalDateTime.now(), flowId, PayEnums.VIP_PAY);
|
||||
return CzgResult.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> rechargePayOrder(String clintIp, OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
|
||||
AssertUtil.isNull(shopInfo, "店铺不存在");
|
||||
AssertUtil.isNull(payParam.getShopUserId(), "请选择付款人后重试");
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "支付失败 该店铺用户不存在");
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
|
||||
AssertUtil.isNull(payParam.getRechargeId(), "请选择充值配置后重试");
|
||||
AssertUtil.isNull(payParam.getRechargeDetailId(), "请选择充值配置后重试");
|
||||
//查询活动Id 获取金额字段
|
||||
MkShopRechargeDetail rechargeDetail = shopRechargeDetailService.getOne(
|
||||
new QueryWrapper().eq(MkShopRechargeDetail::getId, payParam.getRechargeDetailId())
|
||||
.eq(MkShopRechargeDetail::getShopRechargeId, payParam.getRechargeId()));
|
||||
AssertUtil.isNull(rechargeDetail, "充值配置不存在");
|
||||
if (orderInfo.getOrderAmount().compareTo(rechargeDetail.getAmount()) >= 0) {
|
||||
log.info("充值金额小于订单金额,充值金额:{} 订单金额:{}", rechargeDetail.getAmount(), orderInfo.getOrderAmount());
|
||||
return CzgResult.failure("支付失败 充值金额必须大雨订单金额");
|
||||
}
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), PayTypeConstants.SourceType.MEMBER_IN,
|
||||
payOrderNo, rechargeDetail.getAmount(), "", rechargeDetail.getId()));
|
||||
upOrderPayInfo(orderInfo.getId(), PayEnums.VIP_PAY, paymentId,
|
||||
payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.LT_PAY,
|
||||
CzgPayBaseReq.ltPayReq(
|
||||
payOrderNo, "充值并支付",
|
||||
rechargeDetail.getAmount().multiply(PayService.MONEY_RATE).longValue(), payParam.getPayType(),
|
||||
"wechatPay".equals(payParam.getPayType()) ? userInfo.getWechatOpenId() : userInfo.getAlipayOpenId(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Map<String, Object>> h5PayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.orderPay(payParam.getShopId(), orderInfo.getId(), payOrderNo, orderInfo.getOrderAmount(), ""));
|
||||
upOrderPayInfo(orderInfo.getId(), PayEnums.H5_PAY, paymentId, payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.H5_PAY,
|
||||
CzgPayBaseReq.h5PayReq(payOrderNo, "点餐支付", orderInfo.getOrderAmount().multiply(PayService.MONEY_RATE).longValue(), clintIp));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Map<String, Object>> jsPayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.orderPay(payParam.getShopId(), orderInfo.getId(), payOrderNo, orderInfo.getOrderAmount(), ""));
|
||||
upOrderPayInfo(orderInfo.getId(), "aliPay".equals(payParam.getPayType()) ? PayEnums.ALIPAY_MINI : PayEnums.WECHAT_MINI, paymentId,
|
||||
payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.JS_PAY,
|
||||
CzgPayBaseReq.jsPayReq(payOrderNo, "点餐支付", orderInfo.getOrderAmount().multiply(PayService.MONEY_RATE).longValue(),
|
||||
payParam.getPayType(), payParam.getOpenId(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Map<String, Object>> js2PayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
|
||||
OrderInfo orderInfo;
|
||||
if (payParam.getCheckOrderPay().getOrderId() == null) {
|
||||
if (payParam.getCheckOrderPay().getOrderAmount() == null || payParam.getCheckOrderPay().getOrderAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new CzgException("支付金额不合法");
|
||||
}
|
||||
orderInfo = orderInfoCustomService.createPayOrder(payParam.getShopId(), payParam.getCheckOrderPay().getOrderAmount(),
|
||||
payParam.getCheckOrderPay().getRemark());
|
||||
} else {
|
||||
orderInfo = orderInfoService.getById(payParam.getCheckOrderPay().getOrderId());
|
||||
}
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.orderPay(payParam.getShopId(), orderInfo.getId(), payOrderNo, orderInfo.getOrderAmount(), ""));
|
||||
upOrderPayInfo(orderInfo.getId(), "aliPay".equals(payParam.getPayType()) ? PayEnums.ALIPAY_MINI : PayEnums.WECHAT_MINI, paymentId,
|
||||
payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.JS_PAY,
|
||||
CzgPayBaseReq.jsPayReq(payOrderNo, "扫码支付", orderInfo.getOrderAmount().multiply(PayService.MONEY_RATE).longValue(),
|
||||
payParam.getPayType(), payParam.getOpenId(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Map<String, Object>> ltPayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.orderPay(payParam.getShopId(), orderInfo.getId(), payOrderNo, orderInfo.getOrderAmount(), ""));
|
||||
upOrderPayInfo(orderInfo.getId(), "aliPay".equals(payParam.getPayType()) ? PayEnums.ALIPAY_MINI : PayEnums.WECHAT_MINI, paymentId,
|
||||
payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.LT_PAY,
|
||||
CzgPayBaseReq.ltPayReq(payOrderNo, "点餐支付", orderInfo.getOrderAmount().multiply(PayService.MONEY_RATE).longValue(),
|
||||
payParam.getPayType(), payParam.getOpenId(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Map<String, Object>> scanPayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
|
||||
if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
|
||||
throw new CzgException("未开启自定义充值金额");
|
||||
}
|
||||
Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
|
||||
BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
|
||||
payParam.setAmount(amount);
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.orderPay(payParam.getShopId(), orderInfo.getId(), payOrderNo, orderInfo.getOrderAmount(), ""));
|
||||
upOrderPayInfo(orderInfo.getId(), PayEnums.MAIN_SCAN, paymentId,
|
||||
payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.SCAN_PAY,
|
||||
CzgPayBaseReq.scanPayReq(payOrderNo, "点餐支付", orderInfo.getOrderAmount().multiply(PayService.MONEY_RATE).longValue(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(noRollbackFor = PaySuccessException.class)
|
||||
public CzgResult<Map<String, Object>> microPayOrder(OrderPayParamDTO payParam) {
|
||||
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
|
||||
AssertUtil.isBlank(payParam.getAuthCode(), "扫描码不能为空");
|
||||
|
||||
|
||||
if (payParam.getShopUserId() != null) {
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
|
||||
if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
|
||||
throw new CzgException("未开启自定义充值金额");
|
||||
}
|
||||
Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
|
||||
BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
|
||||
payParam.setAmount(amount);
|
||||
}
|
||||
|
||||
String payOrderNo = orderInfo.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
Long paymentId = payService.initPayment(OrderPayment.orderPay(payParam.getShopId(), orderInfo.getId(), payOrderNo, orderInfo.getOrderAmount(), payParam.getAuthCode()));
|
||||
CzgResult<Map<String, Object>> mapCzgResult = payService.pay(payParam.getShopId(), CzgPayEnum.MICRO_PAY,
|
||||
CzgPayBaseReq.microPay(payOrderNo, "点餐支付", orderInfo.getOrderAmount().multiply(PayService.MONEY_RATE).longValue(), payParam.getAuthCode()));
|
||||
if (mapCzgResult.getCode() == 200) {
|
||||
orderInfoCustomService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
|
||||
LocalDateTime.now(), paymentId, PayEnums.BACK_SCAN);
|
||||
} else {
|
||||
upOrderPayInfo(orderInfo.getId(), PayEnums.BACK_SCAN, paymentId,
|
||||
payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
|
||||
}
|
||||
return mapCzgResult;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Object> refundOrderBefore(OrderInfoRefundDTO param) {
|
||||
OrderInfo orderInfo = orderInfoService.getById(param.getOrderId());
|
||||
if (orderInfo.getStatus().equals(OrderStatusEnums.CANCELLED.getCode())) {
|
||||
throw new CzgException("订单已过期不可退单");
|
||||
}
|
||||
boolean isFirstRefund = true;
|
||||
if (orderInfo.getRefundAmount().compareTo(BigDecimal.ZERO) != 0) {
|
||||
isFirstRefund = false;
|
||||
}
|
||||
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
|
||||
Map<String, BigDecimal> returnProMap = new HashMap<>();
|
||||
boolean isPay = true;
|
||||
String refPayOrderNo = "REFO" + IdUtil.getSnowflakeNextId();
|
||||
if (orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
|
||||
isPay = false;
|
||||
refPayOrderNo = "";
|
||||
}
|
||||
if (isPay) {
|
||||
if (shopInfo.getIsReturnPwd().equals(1)) {
|
||||
AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
|
||||
if (!SecureUtil.md5(param.getPwd()).equals(shopInfo.getOperationPwd())) {
|
||||
throw new CzgException("操作密码错误");
|
||||
}
|
||||
}
|
||||
orderInfo.setRefundAmount(orderInfo.getRefundAmount().add(param.getRefundAmount()));
|
||||
if (orderInfo.getRefundAmount().compareTo(orderInfo.getPayAmount()) > 0) {
|
||||
throw new CzgException("退单失败,可退金额不足");
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(param.getRefundDetails())) {
|
||||
for (OrderDetail refundDetail : param.getRefundDetails()) {
|
||||
AssertUtil.isNull(refundDetail.getNum(), "退单数量不能为空");
|
||||
//退款数量
|
||||
BigDecimal refNum = refundDetail.getNum();
|
||||
OrderDetail orderDetail = orderDetailService.getById(refundDetail.getId());
|
||||
//可退数量=订单数量-退单数量-退菜数量
|
||||
BigDecimal returnNum = orderDetail.getNum().subtract(orderDetail.getRefundNum()).subtract(orderDetail.getReturnNum());
|
||||
if (returnNum.compareTo(BigDecimal.ZERO) <= 0 || returnNum.compareTo(refundDetail.getNum()) < 0) {
|
||||
throw new CzgException("退单失败," + orderDetail.getProductName() + "可退数量不足");
|
||||
}
|
||||
refundDetail.setReturnAmount(refundDetail.getNum().multiply(orderDetail.getUnitPrice()).setScale(2, RoundingMode.UP));
|
||||
if (isPay) {
|
||||
orderDetail.setRefundNum(orderDetail.getRefundNum().add(refNum));
|
||||
if (orderDetail.getNum().compareTo(orderDetail.getRefundNum().add(orderDetail.getReturnNum())) == 0) {
|
||||
orderDetail.setStatus(OrderStatusEnums.REFUND.getCode());
|
||||
} else {
|
||||
orderDetail.setStatus(OrderStatusEnums.PART_REFUND.getCode());
|
||||
}
|
||||
} else {
|
||||
orderDetail.setReturnNum(orderDetail.getReturnNum().add(refNum));
|
||||
if (orderDetail.getPackNumber().compareTo(BigDecimal.ZERO) > 0 && orderDetail.getPackNumber().compareTo(orderDetail.getNum().subtract(orderDetail.getReturnNum())) > 0) {
|
||||
orderDetail.setPackNumber(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
|
||||
}
|
||||
}
|
||||
orderDetail.setRefundNo(refPayOrderNo);
|
||||
orderDetail.setRefundRemark(orderDetail.getRefundRemark() + param.getRefundReason());
|
||||
// if (isPay) {
|
||||
orderDetail.setReturnAmount(orderDetail.getReturnAmount().add(refundDetail.getReturnAmount()));
|
||||
if (orderDetail.getReturnAmount().compareTo(orderDetail.getPayAmount()) > 0) {
|
||||
orderDetail.setReturnAmount(orderDetail.getPayAmount());
|
||||
}
|
||||
// }
|
||||
orderDetailService.updateById(orderDetail);
|
||||
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
|
||||
returnProMap.put(Convert.toStr(orderDetail.getProductId()), refundDetail.getNum());
|
||||
}
|
||||
}
|
||||
long count = orderDetailService.queryChain()
|
||||
.eq(OrderDetail::getOrderId, orderInfo.getId())
|
||||
.ne(OrderDetail::getStatus, OrderStatusEnums.REFUND.getCode()).count();
|
||||
if (count > 0 && isPay) {
|
||||
orderInfo.setStatus(OrderStatusEnums.PART_REFUND.getCode());
|
||||
} else if (isPay) {
|
||||
orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
|
||||
}
|
||||
} else {
|
||||
orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
|
||||
List<OrderDetail> orderDetails = orderDetailService.queryChain()
|
||||
.select(OrderDetail::getId, OrderDetail::getProductId, OrderDetail::getNum, OrderDetail::getReturnNum, OrderDetail::getPackAmount, OrderDetail::getReturnNum)
|
||||
.eq(OrderDetail::getOrderId, orderInfo.getId())
|
||||
.list();
|
||||
for (OrderDetail orderDetail : orderDetails) {
|
||||
if (isPay) {
|
||||
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
|
||||
returnProMap.put(Convert.toStr(orderDetail.getProductId()), orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum()));
|
||||
}
|
||||
orderDetail.setReturnAmount(orderDetail.getPayAmount());
|
||||
orderDetail.setRefundNum(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
|
||||
orderDetail.setStatus(OrderStatusEnums.REFUND.getCode());
|
||||
} else {
|
||||
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
|
||||
returnProMap.put(Convert.toStr(orderDetail.getProductId()), orderDetail.getNum().subtract(orderDetail.getReturnNum()));
|
||||
}
|
||||
orderDetail.setReturnNum(orderDetail.getNum());
|
||||
orderDetail.setStatus(OrderStatusEnums.CANCELLED.getCode());
|
||||
}
|
||||
}
|
||||
orderDetailService.updateBatch(orderDetails);
|
||||
}
|
||||
//总退款金额
|
||||
//TODO 退款 券 未处理
|
||||
if (isPay) {
|
||||
orderInfo.setRefundType("cash");
|
||||
//非现金退款
|
||||
if (!param.isCash()) {
|
||||
if (orderInfo.getPayType().equals(PayEnums.VIP_PAY.getValue())) {
|
||||
ShopUser shopUser = shopUserService.getShopUserInfo(orderInfo.getShopId(), orderInfo.getUserId());
|
||||
//会员支付 退钱
|
||||
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
|
||||
.setId(shopUser.getId())
|
||||
.setMoney(param.getRefundAmount())
|
||||
.setType(1)
|
||||
.setRelationId(orderInfo.getId())
|
||||
.setBizEnum(ShopUserFlowBizEnum.ORDER_REFUND);
|
||||
shopUserService.updateMoney(shopUserMoneyEditDTO);
|
||||
} else if (orderInfo.getPayType().equals(PayEnums.CREDIT_PAY.getValue())) {
|
||||
AssertUtil.isNull(orderInfo.getCreditBuyerId(), "挂账单退款失败,未查询到挂账人");
|
||||
buyerOrderService.partRefund(orderInfo.getCreditBuyerId().toString(), orderInfo.getId(), param.getRefundAmount());
|
||||
} else if (!orderInfo.getPayType().equals(PayEnums.CASH_PAY.getValue())) {
|
||||
//退款 param.getRefundAmount()
|
||||
if (orderInfo.getPayOrderId() == null) {
|
||||
throw new CzgException("退款失败,支付记录不存在");
|
||||
}
|
||||
refundOrder(orderInfo.getShopId(), orderInfo.getId(), orderInfo.getPayOrderId(),
|
||||
refPayOrderNo, StrUtil.isBlank(param.getRefundReason()) ? "退款" : param.getRefundReason(), param.getRefundAmount());
|
||||
}
|
||||
orderInfo.setRefundType("payBack");
|
||||
}
|
||||
} else {
|
||||
orderInfo.setOrderAmount(orderInfo.getOrderAmount().subtract(param.getRefundAmount()));
|
||||
}
|
||||
orderInfo.setRefundRemark(orderInfo.getRefundRemark() + param.getRefundReason());
|
||||
orderInfoService.updateById(orderInfo);
|
||||
//退款后续
|
||||
//退款返还库存
|
||||
if (!returnProMap.isEmpty()) {
|
||||
rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderInfo.getId(), "returnProMap", returnProMap)));
|
||||
}
|
||||
refundOrderAfter(orderInfo.getId(), orderInfo.getShopId(), orderInfo.getUserId(), orderInfo.getOrderNo(),
|
||||
orderInfo.getPointsNum(), isFirstRefund, orderInfo.getStatus().equals(OrderStatusEnums.REFUND.getCode()));
|
||||
return CzgResult.success();
|
||||
}
|
||||
|
||||
private void refundOrder(@NonNull Long shopId, @NonNull Long orderId, @NonNull Long payOrderId, @NonNull String refPayOrderNo,
|
||||
@NonNull String refundReason, @NonNull BigDecimal refundAmount) {
|
||||
OrderPayment payment = paymentService.getById(payOrderId);
|
||||
AssertUtil.isNull(payment, "退款失败支付记录不存在");
|
||||
Long refundId = payService.initPayment(OrderPayment.refund(shopId, orderId, PayTypeConstants.SourceType.ORDER,
|
||||
refPayOrderNo, refundAmount, payment.getId(), payment.getPlatformType()));
|
||||
|
||||
CzgResult<RefundRespDTO> refund = payService.refund(shopId, new CzgRefundReq(refPayOrderNo, refundReason, refundAmount.multiply(PayService.MONEY_RATE).longValue(),
|
||||
payment.getAmount().multiply(PayService.MONEY_RATE).longValue(), payment.getOrderNo(), "", payment.getPlatformType()));
|
||||
if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getStatus())) {
|
||||
if (refund.getData() != null && refund.getData().getErrMessage() != null) {
|
||||
throw new CzgException(refund.getData().getErrMessage());
|
||||
}
|
||||
throw new CzgException(refund.getMsg());
|
||||
} else {
|
||||
paymentService.updateChain()
|
||||
.eq(OrderPayment::getId, refundId)
|
||||
.set(OrderPayment::getPayTime, refund.getData().getRefundTime())
|
||||
.set(OrderPayment::getTradeNumber, refund.getData().getThirdRefundNo())
|
||||
.set(OrderPayment::getRespJson, refund.getData().getOriginalData())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
//触发订单退款时 后续处理
|
||||
@Async
|
||||
public void refundOrderAfter(@NonNull Long orderId, @NonNull Long shopId, Long userId, String orderNo,
|
||||
Integer pointsNum, boolean isFirstRefund, boolean isAllRefund) {
|
||||
if (isFirstRefund) {
|
||||
// 退款分销还原
|
||||
FunUtils.safeRunVoid(() -> distributionUserService.refund(orderId, orderNo),
|
||||
"订单id:{} 退款,分销处理失败", orderId);
|
||||
if (userId == null) {
|
||||
return;
|
||||
}
|
||||
FunUtils.safeRunVoid(() -> consumerCouponService.removeConsumerCoupon(shopId, userId, orderId),
|
||||
"订单id:{} 退款,消费赠券回撤处理失败", orderId);
|
||||
FunUtils.safeRunVoid(() -> consumeCashbackService.removeCashback(shopId, userId, orderId, orderNo),
|
||||
"订单id:{} 退款,消费返现扣除处理失败", orderId);
|
||||
FunUtils.safeRunVoid(() -> pointsConfigService.removeConsumeAwardPoints(shopId, userId, orderId, orderNo),
|
||||
"订单id:{} 退款,赠送积分扣除失败", orderId);
|
||||
}
|
||||
if (isAllRefund && userId != null && pointsNum != null && pointsNum > 0) {
|
||||
FunUtils.safeRunVoid(() -> mkPointsUserService.alterPoints(userId, null, shopId, PointsConstant.ADD,
|
||||
pointsNum, orderId, StrUtil.format("订单退款返还{}积分", pointsNum)),
|
||||
"订单id:{} 退款,赠送积分扣除失败", orderId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void upOrderPayInfo(@NonNull Long orderId, @NonNull PayEnums payType, @NotBlank Long paymentId, String remark) {
|
||||
if (paymentId == null) {
|
||||
throw new CzgException("未获取到支付记录");
|
||||
}
|
||||
orderInfoCustomService.updatePayOrderId(orderId, paymentId, payType.getValue(), remark);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,32 +2,36 @@ package com.czg.service.order.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.map.MapProxy;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.UnicodeUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.account.entity.PrintMachine;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import com.czg.config.RedisCst;
|
||||
import com.czg.market.service.OrderInfoService;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.order.entity.PrintMachineLog;
|
||||
import com.czg.order.service.PrintMachineLogService;
|
||||
import com.czg.service.RedisService;
|
||||
import com.czg.service.order.mapper.PrintMachineLogMapper;
|
||||
import com.czg.service.order.print.FeiPrinter;
|
||||
import com.czg.service.order.print.YxyPrinter;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 店铺小票打印记录ServiceImpl
|
||||
@@ -38,139 +42,47 @@ import java.util.*;
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMapper, PrintMachineLog> implements PrintMachineLogService{
|
||||
//请求地址
|
||||
private static final String URL_STR = "https://ioe.car900.com/v1/openApi/dev/customPrint.json";
|
||||
//APPID
|
||||
private static final String APP_ID = "ZF544";
|
||||
//USERCODE
|
||||
private static final String USER_CODE = "ZF544";
|
||||
//APPSECRET
|
||||
private static final String APP_SECRET = "2022bsjZF544GAH";
|
||||
public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMapper, PrintMachineLog> implements PrintMachineLogService {
|
||||
|
||||
public static final String URL = "http://api.feieyun.cn/Api/Open/";//不需要修改
|
||||
@Resource
|
||||
private OrderInfoService orderInfoService;
|
||||
@Lazy
|
||||
@Resource
|
||||
private YxyPrinter yxyPrinter;
|
||||
@Lazy
|
||||
@Resource
|
||||
private FeiPrinter feiPrinter;
|
||||
@Resource
|
||||
private RedisService redisService;
|
||||
|
||||
public static final String USER = "chaozhanggui2022@163.com";//*必填*:账号名
|
||||
public static final String UKEY = "UfWkhXxSkeSSscsU";//*必填*: 飞鹅云后台注册账号后生成的UKEY 【备注:这不是填打印机的KEY】
|
||||
public static final String SN = "960238952";//*必填*:打印机编号,必须要在管理后台里添加打印机或调用API接口添加之后,才能调用API
|
||||
/**
|
||||
* 获取TOKEN值
|
||||
*
|
||||
* @param timestamp 时间戳,13位
|
||||
* @param requestId 请求ID,自定义
|
||||
* @return
|
||||
*/
|
||||
private static Map<String, String> getToken(String timestamp, String requestId) {
|
||||
StringBuilder token = new StringBuilder();
|
||||
StringBuilder encode = new StringBuilder();
|
||||
SortedMap<String, Object> map = new TreeMap<>();
|
||||
map.put("appId", APP_ID);
|
||||
map.put("timestamp", timestamp);
|
||||
map.put("requestId", requestId);
|
||||
map.put("userCode", USER_CODE);
|
||||
for (Map.Entry<String, Object> next : map.entrySet()) {
|
||||
String key = next.getKey();
|
||||
Object value = next.getValue();
|
||||
token.append(key).append(value);
|
||||
encode.append(key).append("=").append(value).append("&");
|
||||
Map<Integer, String> yxxStatusMap = Map.of(
|
||||
0, "离线(设备上线后自动补打)",
|
||||
1, "在线",
|
||||
2, "获取失败",
|
||||
3, "未激活",
|
||||
4, "设备已禁用");
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void save(PrintMachine config, String bizType, String printContent, String respJson) {
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
System.out.println("token" + token);
|
||||
Map<String, String> finalMap = new HashMap<>();
|
||||
finalMap.put("ENCODE", encode.toString());
|
||||
System.out.println("+++++++++++++++" + token + APP_SECRET);
|
||||
finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
|
||||
return finalMap;
|
||||
save(null, config, bizType, printContent, respJson);
|
||||
}
|
||||
/**
|
||||
* 检查打印状态
|
||||
*
|
||||
* @param devName 设备名称,(唯一) 对应配置表中的address字段即(IP地址/打印机编号)
|
||||
* @param taskId 打印任务id,用于复查打印状态,云想印=orderId
|
||||
* @return
|
||||
*/
|
||||
public static String checkPrintStatus(String devName, String taskId) {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
Map<String, String> param = getToken(time, uuid);
|
||||
String token = param.get("TOKEN");
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
|
||||
paramMap.put("devName", devName);
|
||||
paramMap.put("orderId", taskId);
|
||||
paramMap.put("token", token);
|
||||
paramMap.put("appId", APP_ID);
|
||||
paramMap.put("timestamp", time);
|
||||
paramMap.put("requestId", uuid);
|
||||
paramMap.put("userCode", USER_CODE);
|
||||
|
||||
return HttpUtil.get("https://ioe.car900.com/v1/openApi/dev/findOrder.json", paramMap, 1000 * 5);
|
||||
}
|
||||
private static String signature(String USER, String UKEY, String STIME) {
|
||||
return DigestUtils.sha1Hex(USER + UKEY + STIME);
|
||||
}
|
||||
/**
|
||||
* 检查飞鹅打印机打印任务是否已打印
|
||||
*
|
||||
* @param printOrderId 打印订单编号
|
||||
* @return null-未知错误,true-已打印,false-未打印
|
||||
*/
|
||||
public static Boolean checkFPrintStatus(String printOrderId) {
|
||||
String STIME = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("user", USER);
|
||||
paramMap.put("stime", STIME);
|
||||
paramMap.put("sig", signature(USER, UKEY, STIME));
|
||||
paramMap.put("apiname", "Open_queryOrderState");
|
||||
paramMap.put("orderid", printOrderId);
|
||||
Boolean ret;
|
||||
try {
|
||||
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
|
||||
//成功 {"msg":"ok","ret":0,"data":true,"serverExecutedTime":4}
|
||||
//失败 {"msg":"ok","ret":0,"data":false,"serverExecutedTime":4}
|
||||
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
|
||||
ret = json.getBool("data");
|
||||
} catch (Exception e) {
|
||||
ret = null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* 检查飞鹅打印机是否在线
|
||||
*
|
||||
* @param sn 设备编号
|
||||
* @return 在线,工作状态正常。/离线。/未知错误
|
||||
*/
|
||||
public static String checkOnline(String sn) {
|
||||
String STIME = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("user", USER);
|
||||
paramMap.put("stime", STIME);
|
||||
paramMap.put("sig", signature(USER, UKEY, STIME));
|
||||
paramMap.put("apiname", "Open_queryPrinterStatus");
|
||||
paramMap.put("sn", sn);
|
||||
String msg;
|
||||
try {
|
||||
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
|
||||
//成功 开机 {"msg":"ok","ret":0,"data":"在线,工作状态正常。","serverExecutedTime":4}
|
||||
//成功 离线 {"msg":"ok","ret":0,"data":"离线。","serverExecutedTime":7}
|
||||
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
|
||||
msg = json.getStr("data");
|
||||
} catch (Exception e) {
|
||||
msg = "未知错误";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
/**
|
||||
* 保存打印记录
|
||||
*
|
||||
* @param orderId 订单Id
|
||||
* @param config 打印机配置
|
||||
* @param bizType 业务类型
|
||||
* @param printContent 打印内容
|
||||
* @param respJson 打印机响应结果
|
||||
*/
|
||||
@Async
|
||||
public void save(PrintMachine config, String bizType, String printContent, Object respJson) {
|
||||
@Override
|
||||
public void save(Long orderId, PrintMachine config, String bizType, String printContent, String respJson) {
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
@@ -179,51 +91,41 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
|
||||
int failFlag = 0;
|
||||
String respCode = "0";
|
||||
String respMsg = "打印中";
|
||||
|
||||
Map<Integer, String> yxxStatusMap = MapUtil.builder(0, "离线(设备上线后自动补打)").put(1, "在线").put(2, "获取失败").put(3, "未激活").put(4, "设备已禁用").build();
|
||||
JSONObject resp = JSONObject.parseObject(respJson);
|
||||
// 云想印
|
||||
if ("云享印".equals(config.getContentType())) {
|
||||
cn.hutool.json.JSONObject resp = JSONUtil.parseObj(respJson);
|
||||
int code = resp.getInt("code");
|
||||
cn.hutool.json.JSONObject data = resp.getJSONObject("data").getJSONObject("data");
|
||||
if ("云想印".equals(config.getContentType())) {
|
||||
int code = resp.getIntValue("code");
|
||||
JSONObject respData = resp.getJSONObject("data");
|
||||
JSONObject data = respData.getJSONObject("data");
|
||||
//设备状态,0: 离线, 1: 在线, 2: 获取失败, 3:未激活, 4:设备已禁用
|
||||
int status = data.getInt("status");
|
||||
int status = data.getIntValue("status");
|
||||
if (code != 0) {
|
||||
failFlag = 1;
|
||||
respCode = code + "";
|
||||
respMsg = resp.getStr("msg");
|
||||
respMsg = resp.getString("msg");
|
||||
} else if (status != 1) {
|
||||
failFlag = 1;
|
||||
respCode = code + "";
|
||||
|
||||
respMsg = status + "_" + yxxStatusMap.get(status);
|
||||
}
|
||||
if (code == 0) {
|
||||
String taskId = resp.getJSONObject("data").getStr("orderId");
|
||||
entity.setTaskId(taskId);
|
||||
entity.setTaskId(respData.getString("orderId"));
|
||||
}
|
||||
// 飞鹅云打印机暂时没有适配,先return不做打印记录
|
||||
} else if ("飞鹅".equals(config.getContentType())) {
|
||||
cn.hutool.json.JSONObject resp = JSONUtil.parseObj(respJson);
|
||||
int ret = resp.getInt("ret");
|
||||
int ret = resp.getIntValue("ret");
|
||||
if (ret != 0) {
|
||||
failFlag = 1;
|
||||
respCode = ret + "";
|
||||
respMsg = resp.getStr("msg");
|
||||
respMsg = resp.getString("msg");
|
||||
} else {
|
||||
String printOrderId = resp.getStr("data");
|
||||
entity.setTaskId(printOrderId);
|
||||
entity.setTaskId(resp.getString("data"));
|
||||
}
|
||||
} else {
|
||||
// 其他打印机暂时没有适配,先return不做打印记录
|
||||
return;
|
||||
}
|
||||
entity.setBizType(bizType);
|
||||
// entity.setCreateUserId(config.getCurrentUserId());
|
||||
// entity.setCreateUserName(config.getCurrentUserName());
|
||||
// if (StrUtil.isNotBlank(config.getCurrentUserNickName())) {
|
||||
// entity.setCreateUserName(StrUtil.concat(true, config.getCurrentUserNickName(), " | ", config.getCurrentUserName()));
|
||||
// }
|
||||
entity.setPrintContent(printContent);
|
||||
entity.setCreateTime(DateUtil.date().toLocalDateTime());
|
||||
if (failFlag == 0) {
|
||||
@@ -233,66 +135,213 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
|
||||
entity.setRespCode(respCode);
|
||||
entity.setRespMsg(respMsg);
|
||||
super.save(entity);
|
||||
ThreadUtil.execAsync(() -> checkPrintStatus(orderId, config, entity));
|
||||
}
|
||||
|
||||
// 云想印
|
||||
if ("云享印".equals(config.getContentType())) {
|
||||
// 延迟3ms,复查打印状态 (用户可以根据设备信息查询到当前设备的在线情况(注:该接口只能提供参考,设备的离线状态是在设备离线3分钟后才会生效))
|
||||
ThreadUtil.safeSleep(1000 * 5);
|
||||
String jsonStr = checkPrintStatus(config.getAddress(), entity.getTaskId());
|
||||
cn.hutool.json.JSONObject resp = JSONUtil.parseObj(jsonStr);
|
||||
int code = resp.getInt("code");
|
||||
if (code == 0) {
|
||||
cn.hutool.json.JSONObject data = resp.getJSONObject("data");
|
||||
boolean status = data.containsKey("status");
|
||||
if (!status) {
|
||||
/**
|
||||
* 类级别成员变量:基于虚拟线程的固定大小(5)定时线程池
|
||||
* // Java 21+ 虚拟线程工厂,支持命名
|
||||
*/
|
||||
private final ScheduledExecutorService virtualThreadScheduler = Executors.newScheduledThreadPool(
|
||||
5,
|
||||
Thread.ofVirtual().name("print-query-vt-", 0).factory()
|
||||
);
|
||||
|
||||
/**
|
||||
* 打印机状态查询(解决 retryFuture 爆红问题 + 虚拟线程 + 轮询重试)
|
||||
*
|
||||
* @param orderId 订单Id
|
||||
* @param config 打印机配置
|
||||
* @param entity 打印日志实体
|
||||
*/
|
||||
public void checkPrintStatus(Long orderId, PrintMachine config, PrintMachineLog entity) {
|
||||
// 最大重试次数
|
||||
int maxRetryTimes = 5;
|
||||
AtomicInteger executedTimes = new AtomicInteger(0);
|
||||
|
||||
// 原子引用包装ScheduledFuture,用于后续取消轮询
|
||||
AtomicReference<ScheduledFuture<?>> retryFutureRef = new AtomicReference<>();
|
||||
|
||||
// 核心查询任务(修正后,逻辑内聚)
|
||||
Runnable printQueryTask = () -> {
|
||||
int currentTimes = executedTimes.incrementAndGet();
|
||||
boolean isPrintSuccess = false;
|
||||
boolean isLastTask = false;
|
||||
|
||||
try {
|
||||
// 1. 云想印打印机状态查询
|
||||
if ("云想印".equals(config.getContentType())) {
|
||||
String jsonStr = yxyPrinter.checkPrintStatus(config.getAddress(), entity.getTaskId());
|
||||
log.info("云想印打印状态查询结果(第{}次,虚拟线程:{}):{}",
|
||||
currentTimes, Thread.currentThread().getName(), jsonStr);
|
||||
JSONObject resp = JSONObject.parseObject(jsonStr);
|
||||
int code = resp.getIntValue("code");
|
||||
if (code == 0) {
|
||||
JSONObject data = resp.getJSONObject("data");
|
||||
if (data.containsKey("status")) {
|
||||
isPrintSuccess = data.getBooleanValue("status", false);
|
||||
updatePrintLogEntity(entity, isPrintSuccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. 飞鹅云打印机状态查询
|
||||
else if ("飞鹅".equals(config.getContentType())) {
|
||||
Boolean success = feiPrinter.checkFPrintStatus(entity.getTaskId());
|
||||
if (success == null) {
|
||||
entity.setFailFlag(1);
|
||||
entity.setRespMsg("打印失败,未知错误");
|
||||
entity.setPrintTime(null);
|
||||
} else if (success) {
|
||||
isPrintSuccess = true;
|
||||
updatePrintLogEntity(entity, true);
|
||||
} else {
|
||||
String msg = feiPrinter.checkOnline(entity.getAddress());
|
||||
if (msg.indexOf("在线,工作状态正常") > 0) {
|
||||
isPrintSuccess = true;
|
||||
updatePrintLogEntity(entity, true);
|
||||
} else {
|
||||
isPrintSuccess = false;
|
||||
entity.setFailFlag(1);
|
||||
entity.setPrintTime(null);
|
||||
entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", msg));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("打印类型为其他类型,终止打印状态查询轮询任务");
|
||||
ScheduledFuture<?> future = retryFutureRef.get();
|
||||
if (future != null && !future.isCancelled()) {
|
||||
boolean cancelSuccess = future.cancel(false); // 取消后续轮询(不中断当前任务)
|
||||
log.info("其他打印类型,取消轮询任务:{}", cancelSuccess ? "成功" : "失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 打印成功:取消后续轮询任务
|
||||
if (isPrintSuccess) {
|
||||
isLastTask = true;
|
||||
ScheduledFuture<?> future = retryFutureRef.get();
|
||||
if (future != null && !future.isCancelled()) {
|
||||
future.cancel(false); // 不中断当前任务,仅取消后续任务
|
||||
}
|
||||
return;
|
||||
}
|
||||
boolean success = data.getBool("status", false);
|
||||
if (entity.getFailFlag() == 0 && success) {
|
||||
entity.setFailFlag(0);
|
||||
entity.setRespMsg("打印成功");
|
||||
entity.setPrintTime(entity.getCreateTime());
|
||||
} else if (entity.getFailFlag() == 1 && success) {
|
||||
entity.setFailFlag(0);
|
||||
entity.setPrintTime(DateUtil.date().toLocalDateTime());
|
||||
entity.setRespMsg("打印成功");
|
||||
// 如果设备在线 and 休眠5秒后查询结果是未打印,即视为设备已离线,云端3分钟后才会同步到离线信息
|
||||
} else if (entity.getFailFlag() == 0 && !success) {
|
||||
entity.setFailFlag(1);
|
||||
entity.setPrintTime(null);
|
||||
entity.setRespMsg("0_离线(设备上线后自动补打)");
|
||||
} else {
|
||||
entity.setFailFlag(1);
|
||||
entity.setPrintTime(null);
|
||||
entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", entity.getRespMsg()));
|
||||
|
||||
// 4. 达到最大重试次数:取消后续轮询任务
|
||||
if (currentTimes >= maxRetryTimes) {
|
||||
isLastTask = true;
|
||||
ScheduledFuture<?> future = retryFutureRef.get();
|
||||
if (future != null && !future.isCancelled()) {
|
||||
future.cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("第{}次打印机状态查询异常(虚拟线程:{})",
|
||||
currentTimes, Thread.currentThread().getName(), e);
|
||||
// 异常时达到最大重试次数,同样取消任务
|
||||
if (currentTimes >= maxRetryTimes) {
|
||||
ScheduledFuture<?> future = retryFutureRef.get();
|
||||
if (future != null && !future.isCancelled()) {
|
||||
boolean cancelSuccess = future.cancel(false);
|
||||
log.info("查询异常且达到最大重试次数,取消轮询任务:{}", cancelSuccess ? "成功" : "失败");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
//仅当是最后一次任务时,才执行更新操作
|
||||
if (isLastTask) {
|
||||
super.updateById(entity);
|
||||
updateOrderEntity(orderId, config, isPrintSuccess);
|
||||
}
|
||||
super.updateById(entity);
|
||||
}
|
||||
// 飞鹅云打印机
|
||||
} else if ("飞鹅".equals(config.getContentType())) {
|
||||
ThreadUtil.safeSleep(1000 * 5);
|
||||
Boolean success = checkFPrintStatus(entity.getTaskId());
|
||||
if (success == null) {
|
||||
entity.setFailFlag(1);
|
||||
entity.setRespMsg("打印失败,未知错误");
|
||||
} else if (success) {
|
||||
entity.setFailFlag(0);
|
||||
entity.setPrintTime(DateUtil.date().toLocalDateTime());
|
||||
entity.setRespMsg("打印成功");
|
||||
};
|
||||
|
||||
// 修正:统一使用scheduleAtFixedRate,避免任务重复执行
|
||||
// 首次延迟10秒执行,后续每隔30秒执行一次(符合原逻辑的首次查询延迟,后续轮询间隔)
|
||||
ScheduledFuture<?> retryFuture = virtualThreadScheduler.scheduleAtFixedRate(
|
||||
printQueryTask,
|
||||
10,
|
||||
30,
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
|
||||
// 修正:先赋值AtomicReference,再让任务可能执行,避免线程安全隐患
|
||||
retryFutureRef.set(retryFuture);
|
||||
// 修正:关闭钩子仅注册一次(通过静态代码块或类初始化时注册,避免重复注册)
|
||||
registerShutdownHookOnce();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新状态
|
||||
*/
|
||||
private void updateOrderEntity(Long orderId, PrintMachine config, boolean isPrintSuccess) {
|
||||
redisService.runFunAndCheckKey(() -> {
|
||||
OrderInfo orderInfo = orderInfoService.getOne(query().select(OrderInfo::getPrintStatus).eq(OrderInfo::getId, orderId));
|
||||
if (orderInfo == null) {
|
||||
orderInfo = new OrderInfo();
|
||||
}
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("id", config.getId());
|
||||
jsonObject.put("name", config.getName());
|
||||
jsonObject.put("time", LocalDateTimeUtil.formatNormal(LocalDateTime.now()));
|
||||
orderInfo.upPrintStatus(jsonObject, isPrintSuccess);
|
||||
orderInfoService.update(orderInfo, query().eq(OrderInfo::getId, orderId));
|
||||
return orderInfo;
|
||||
}, RedisCst.getLockKey("UP_ORDER_PRINT", orderId));
|
||||
redisService.del("order:print:" + orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一更新打印日志实体
|
||||
*
|
||||
* @param entity 打印日志实体
|
||||
* @param isPrintSuccess 是否打印成功
|
||||
*/
|
||||
private void updatePrintLogEntity(PrintMachineLog entity, boolean isPrintSuccess) {
|
||||
if (isPrintSuccess) {
|
||||
entity.setFailFlag(0);
|
||||
entity.setRespMsg("打印成功");
|
||||
entity.setPrintTime(entity.getFailFlag() == 0 ? entity.getCreateTime() : DateUtil.date().toLocalDateTime());
|
||||
} else {
|
||||
entity.setFailFlag(1);
|
||||
entity.setPrintTime(null);
|
||||
if (entity.getFailFlag() == 0) {
|
||||
entity.setRespMsg("0_离线(设备上线后自动补打)");
|
||||
} else {
|
||||
String msg = checkOnline(entity.getAddress());
|
||||
if (msg.indexOf("在线,工作状态正常") > 0) {
|
||||
entity.setFailFlag(0);
|
||||
entity.setPrintTime(DateUtil.date().toLocalDateTime());
|
||||
entity.setRespMsg("打印成功");
|
||||
} else {
|
||||
entity.setFailFlag(1);
|
||||
entity.setPrintTime(null);
|
||||
entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", msg));
|
||||
}
|
||||
entity.setRespMsg(entity.getRespMsg());
|
||||
}
|
||||
super.updateById(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// 静态标识,确保关闭钩子仅注册一次
|
||||
private static volatile boolean shutdownHookRegistered = false;
|
||||
// 锁对象,保证线程安全
|
||||
private static final Object HOOK_LOCK = new Object();
|
||||
|
||||
/**
|
||||
* 统一注册JVM关闭钩子(仅执行一次)
|
||||
*/
|
||||
private void registerShutdownHookOnce() {
|
||||
if (!shutdownHookRegistered) {
|
||||
synchronized (HOOK_LOCK) {
|
||||
// 双重校验锁,避免多线程下重复注册
|
||||
if (!shutdownHookRegistered) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
if (virtualThreadScheduler != null && !virtualThreadScheduler.isShutdown()) {
|
||||
virtualThreadScheduler.shutdown();
|
||||
try {
|
||||
if (!virtualThreadScheduler.awaitTermination(10, TimeUnit.SECONDS)) {
|
||||
log.warn("虚拟线程调度器10秒内未关闭,强制关闭...");
|
||||
virtualThreadScheduler.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("等待虚拟线程调度器终止时被中断,强制关闭", e);
|
||||
virtualThreadScheduler.shutdownNow();
|
||||
Thread.currentThread().interrupt(); // 保留中断状态
|
||||
}
|
||||
}
|
||||
}, "PrinterScheduler-ShutdownHook"));
|
||||
shutdownHookRegistered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package com.czg.service.order.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.EntryManager;
|
||||
import com.czg.OcrUtils;
|
||||
import com.czg.PayCst;
|
||||
import com.czg.config.RabbitPublisher;
|
||||
import com.czg.constants.ParamCodeCst;
|
||||
import com.czg.dto.req.*;
|
||||
import com.czg.order.entity.ShopDirectMerchant;
|
||||
import com.czg.service.order.dto.AggregateMerchantVO;
|
||||
import com.czg.service.order.dto.MerchantQueryDTO;
|
||||
import com.czg.service.order.mapper.ShopDirectMerchantMapper;
|
||||
import com.czg.service.order.service.ShopDirectMerchantService;
|
||||
import com.czg.system.service.SysParamsService;
|
||||
import com.czg.utils.FunUtils;
|
||||
import com.czg.utils.PageUtil;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* 商户进件 服务层实现。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-07
|
||||
*/
|
||||
@Service
|
||||
public class ShopDirectMerchantServiceImpl extends ServiceImpl<ShopDirectMerchantMapper, ShopDirectMerchant> implements ShopDirectMerchantService {
|
||||
|
||||
@Resource
|
||||
private RabbitPublisher rabbitPublisher;
|
||||
@DubboReference
|
||||
private SysParamsService sysParamsService;
|
||||
|
||||
|
||||
// 全局原子计数器,按天重置(避免数值过大)
|
||||
private static final AtomicLong COUNTER = new AtomicLong(0);
|
||||
// 记录上一次的日期,用于重置计数器
|
||||
private static String LAST_DATE = DateUtil.format(new Date(), "yyyyMMdd");
|
||||
|
||||
@Override
|
||||
public JSONObject getInfoByImg(String url, String type) throws Exception {
|
||||
Map<String, String> aliOssKeys = sysParamsService.getParamsByMap("ali_oss_key_set", ParamCodeCst.ALI_OSS_KEY_SET);
|
||||
return OcrUtils.getInfoByImg(aliOssKeys.get(ParamCodeCst.AliYun.ALI_SMS_KEY), aliOssKeys.get(ParamCodeCst.AliYun.ALI_SMS_SECRET), url, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ShopDirectMerchant> getEntryList(MerchantQueryDTO queryParam) {
|
||||
PageHelper.startPage(queryParam.getPage(), queryParam.getSize());
|
||||
List<ShopDirectMerchant> entryList = mapper.getEntryList(queryParam);
|
||||
return PageUtil.convert(new PageInfo<>(entryList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregateMerchantVO getEntry(Long shopId) {
|
||||
ShopDirectMerchant merchant = getOne(query()
|
||||
.eq(ShopDirectMerchant::getShopId, shopId));
|
||||
if (merchant == null) {
|
||||
return null;
|
||||
}
|
||||
return convertVO(merchant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean entryManager(AggregateMerchantDto reqDto) {
|
||||
boolean isSave = false;
|
||||
boolean result;
|
||||
if (StrUtil.isBlank(reqDto.getMerchantCode())) {
|
||||
reqDto.setMerchantCode(getMerchantCode());
|
||||
isSave = true;
|
||||
}
|
||||
EntryManager.verifyEntryParam(reqDto);
|
||||
|
||||
|
||||
ShopDirectMerchant merchant = new ShopDirectMerchant();
|
||||
merchant.setShopId(reqDto.getShopId());
|
||||
merchant.setMerchantCode(reqDto.getMerchantCode());
|
||||
merchant.setLicenceNo(reqDto.getBusinessLicenceInfo().getLicenceNo());
|
||||
|
||||
MerchantBaseInfoDto merchantBaseInfo = reqDto.getMerchantBaseInfo();
|
||||
merchant.setAlipayAccount(merchantBaseInfo.getAlipayAccount());
|
||||
merchant.setUserType(merchantBaseInfo.getUserType());
|
||||
merchant.setShortName(merchantBaseInfo.getShortName());
|
||||
|
||||
merchant.setMerchantBaseInfo(JSONObject.toJSONString(reqDto.getMerchantBaseInfo()));
|
||||
merchant.setLegalPersonInfo(JSONObject.toJSONString(reqDto.getLegalPersonInfo()));
|
||||
merchant.setBusinessLicenceInfo(JSONObject.toJSONString(reqDto.getBusinessLicenceInfo()));
|
||||
merchant.setStoreInfo(JSONObject.toJSONString(reqDto.getStoreInfo()));
|
||||
merchant.setSettlementInfo(JSONObject.toJSONString(reqDto.getSettlementInfo()));
|
||||
|
||||
if (isSave) {
|
||||
merchant.setAlipayStatus(PayCst.EntryStatus.WAIT);
|
||||
merchant.setWechatStatus(PayCst.EntryStatus.WAIT);
|
||||
result = save(merchant);
|
||||
} else {
|
||||
ShopDirectMerchant directMerchant = getById(reqDto.getShopId());
|
||||
if (directMerchant.getAlipayStatus().equals(PayCst.EntryStatus.INIT) || directMerchant.getAlipayStatus().equals(PayCst.EntryStatus.REJECTED)) {
|
||||
merchant.setAlipayStatus(PayCst.EntryStatus.WAIT);
|
||||
}
|
||||
if (directMerchant.getWechatStatus().equals(PayCst.EntryStatus.INIT) || directMerchant.getWechatStatus().equals(PayCst.EntryStatus.REJECTED)) {
|
||||
merchant.setWechatStatus(PayCst.EntryStatus.WAIT);
|
||||
}
|
||||
result = updateById(merchant);
|
||||
}
|
||||
//发送进件队列消息
|
||||
FunUtils.transactionSafeRun(() -> rabbitPublisher.sendEntryManagerMsg(reqDto.getShopId() + ":" + merchant.getLicenceNo()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String getMerchantCode() {
|
||||
Date now = new Date();
|
||||
// 1. 获取当前日期(yyyyMMdd)
|
||||
String currentDate = DateUtil.format(now, "yyyyMMdd");
|
||||
// 2. 每天重置计数器,避免数值溢出
|
||||
synchronized (COUNTER) {
|
||||
if (!currentDate.equals(LAST_DATE)) {
|
||||
COUNTER.set(0);
|
||||
LAST_DATE = currentDate;
|
||||
}
|
||||
}
|
||||
// 3. 原子递增,获取唯一序号(同一毫秒内不会重复)
|
||||
long seq = COUNTER.incrementAndGet();
|
||||
// 4. 时间戳(毫秒级)+ 6位序号(补零)
|
||||
String timeStr = DateUtil.format(now, "yyyyMMddHHmmss");
|
||||
String seqStr = String.format("%03d", seq);
|
||||
return "CZG" + timeStr + seqStr;
|
||||
}
|
||||
|
||||
|
||||
public AggregateMerchantVO convertVO(ShopDirectMerchant entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AggregateMerchantVO vo = new AggregateMerchantVO();
|
||||
vo.setShopId(entity.getShopId());
|
||||
vo.setMerchantCode(entity.getMerchantCode());
|
||||
vo.setShopName(entity.getShopName());
|
||||
|
||||
// 解析JSON字段
|
||||
vo.setMerchantBaseInfo(JSONObject.parseObject(entity.getMerchantBaseInfo(), MerchantBaseInfoDto.class));
|
||||
vo.setLegalPersonInfo(JSONObject.parseObject(entity.getLegalPersonInfo(), LegalPersonInfoDto.class));
|
||||
vo.setBusinessLicenceInfo(JSONObject.parseObject(entity.getBusinessLicenceInfo(), BusinessLicenceInfoDto.class));
|
||||
vo.setStoreInfo(JSONObject.parseObject(entity.getStoreInfo(), StoreInfoDto.class));
|
||||
vo.setSettlementInfo(JSONObject.parseObject(entity.getSettlementInfo(), SettlementInfoDto.class));
|
||||
|
||||
// 设置其他字段
|
||||
vo.setUserType(entity.getUserType());
|
||||
vo.setShortName(entity.getShortName());
|
||||
vo.setAlipayAccount(entity.getAlipayAccount());
|
||||
vo.setCreateTime(entity.getCreateTime());
|
||||
vo.setUpdateTime(entity.getUpdateTime());
|
||||
vo.setWechatApplyId(entity.getWechatApplyId());
|
||||
vo.setWechatStatus(entity.getWechatStatus());
|
||||
vo.setWechatErrorMsg(entity.getWechatErrorMsg());
|
||||
vo.setWechatSignUrl(entity.getWechatSignUrl());
|
||||
vo.setAlipayOrderId(entity.getAlipayOrderId());
|
||||
vo.setAlipayStatus(entity.getAlipayStatus());
|
||||
vo.setAlipayErrorMsg(entity.getAlipayErrorMsg());
|
||||
vo.setAlipaySignUrl(entity.getAlipaySignUrl());
|
||||
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.czg.service.order.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.constants.SystemConstants;
|
||||
import com.czg.order.dto.ShopMerchantDTO;
|
||||
import com.czg.order.entity.ShopDirectMerchant;
|
||||
import com.czg.order.entity.ShopMerchant;
|
||||
import com.czg.order.service.ShopMerchantService;
|
||||
import com.czg.pay.AlipayAuthInfoDto;
|
||||
import com.czg.pay.NativeMerchantDTO;
|
||||
import com.czg.pay.PolyMerchantDTO;
|
||||
import com.czg.service.order.mapper.ShopMerchantMapper;
|
||||
import com.czg.service.order.service.ShopDirectMerchantService;
|
||||
import com.czg.utils.AssertUtil;
|
||||
import com.czg.utils.CzgStrUtils;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 第三方商户进件 服务层实现。
|
||||
*
|
||||
* @author Administrator
|
||||
* @since 2025-02-11
|
||||
*/
|
||||
@CacheConfig(cacheNames = "shop:merchant")
|
||||
@Service
|
||||
public class ShopMerchantServiceImpl extends ServiceImpl<ShopMerchantMapper, ShopMerchant> implements ShopMerchantService {
|
||||
|
||||
@Resource
|
||||
private ShopDirectMerchantService shopDirectMerchantService;
|
||||
@DubboReference
|
||||
private ShopInfoService shopInfoService;
|
||||
|
||||
@Override
|
||||
public ShopMerchantDTO detail(Long shopId) {
|
||||
ShopMerchantDTO shopMerchantVO = new ShopMerchantDTO();
|
||||
ShopMerchant one = getOne(query().eq(ShopMerchant::getShopId, shopId));
|
||||
if (one == null) {
|
||||
return null;
|
||||
}
|
||||
shopMerchantVO.setShopId(shopId);
|
||||
shopMerchantVO.setChannel(one.getChannel());
|
||||
shopMerchantVO.setRelatedId(one.getRelatedId());
|
||||
if (StrUtil.isNotBlank(one.getNativePayJson())) {
|
||||
shopMerchantVO.setNativeMerchantDTO(JSONObject.parseObject(one.getNativePayJson(), NativeMerchantDTO.class));
|
||||
}
|
||||
if (StrUtil.isNotBlank(one.getPolyPayJson())) {
|
||||
shopMerchantVO.setPolyMerchantDTO(JSONObject.parseObject(one.getPolyPayJson(), PolyMerchantDTO.class));
|
||||
}
|
||||
if (one.getRelatedId() != null) {
|
||||
shopMerchantVO.setShopDirectMerchant(shopDirectMerchantService.getOne(query().eq(ShopDirectMerchant::getShopId, one.getRelatedId())));
|
||||
}
|
||||
return shopMerchantVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* * shopId 修改的店铺Id
|
||||
* * relatedLicenceNo 关联值 原生native必填 对应 tb_shop_direct_merchant 的 licence_no营业执照
|
||||
* * channel {@link com.czg.constant.PayChannelCst}
|
||||
* * jsonObject 支付参数 详情
|
||||
* * isUp 是否要修改 传否时 如果存在支付数据 且与当前渠道不一致 则不修改
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(key = "#shopMerchantParam.shopId")
|
||||
public Boolean editEntry(ShopMerchantDTO shopMerchantParam, boolean isUp) {
|
||||
ShopMerchant shopMerchant = getOne(query().eq(ShopMerchant::getShopId, shopMerchantParam.getShopId()));
|
||||
if (shopMerchant == null) {
|
||||
shopMerchant = new ShopMerchant();
|
||||
shopMerchant.setAlipayAppId(SystemConstants.PayType.ALIPAY_APP_ID);
|
||||
shopMerchant.setWechatAppId(SystemConstants.PayType.WECHAT_APP_ID);
|
||||
shopMerchant.setRelatedId(shopMerchantParam.getShopId());
|
||||
}
|
||||
shopMerchant.setShopId(shopMerchantParam.getShopId());
|
||||
if (isUp) {
|
||||
shopMerchant.setChannel(CzgStrUtils.getStrOrNull(shopMerchantParam.getChannel()));
|
||||
shopMerchant.setRelatedId(shopMerchantParam.getRelatedId());
|
||||
if (shopMerchantParam.getRelatedId() == null || !shopMerchantParam.getRelatedId().equals(shopMerchant.getRelatedId())) {
|
||||
ShopDirectMerchant shopDirectMerchant = shopDirectMerchantService.getById(shopMerchantParam.getRelatedId());
|
||||
if (shopDirectMerchant != null) {
|
||||
NativeMerchantDTO nativeMerchantDTO = new NativeMerchantDTO();
|
||||
nativeMerchantDTO.setWechatMerchantId(shopDirectMerchant.getWechatMerchantId());
|
||||
nativeMerchantDTO.setAlipayMerchantId(shopDirectMerchant.getAlipayMerchantId());
|
||||
if (StrUtil.isNotBlank(shopDirectMerchant.getAlipayAuthInfo())) {
|
||||
AlipayAuthInfoDto alipayAuthInfoDto = JSONObject.parseObject(shopDirectMerchant.getAlipayAuthInfo(), AlipayAuthInfoDto.class);
|
||||
nativeMerchantDTO.setAlipayAuthInfo(alipayAuthInfoDto);
|
||||
}
|
||||
shopMerchant.setNativePayJson(JSONObject.toJSONString(nativeMerchantDTO));
|
||||
} else {
|
||||
shopMerchant.setNativePayJson(null);
|
||||
shopMerchant.setWechatAppId(null);
|
||||
shopMerchant.setAlipayAppId(null);
|
||||
}
|
||||
}
|
||||
if (shopMerchantParam.getPolyMerchantDTO() != null) {
|
||||
shopMerchant.setPolyPayJson(JSONObject.toJSONString(shopMerchantParam.getPolyMerchantDTO()));
|
||||
}
|
||||
} else {
|
||||
//只有进件会进入这里
|
||||
if (shopMerchant.getRelatedId() == null) {
|
||||
shopMerchant.setRelatedId(shopMerchantParam.getShopId());
|
||||
}
|
||||
if (StrUtil.isBlank(shopMerchant.getNativePayJson()) && shopMerchantParam.getNativeMerchantDTO() != null) {
|
||||
shopMerchant.setNativePayJson(JSONObject.toJSONString(shopMerchantParam.getNativeMerchantDTO()));
|
||||
}
|
||||
}
|
||||
if (shopMerchant.getId() == null) {
|
||||
return save(shopMerchant);
|
||||
} else {
|
||||
return updateById(shopMerchant, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(allEntries = true)
|
||||
public void upMerchant(@NotBlank Long relatedId, @NotNull NativeMerchantDTO nativeMerchantDTO) {
|
||||
ShopMerchant upShopMerchant = new ShopMerchant();
|
||||
upShopMerchant.setAlipayAppId(nativeMerchantDTO.getAlipayMerchantId());
|
||||
upShopMerchant.setWechatAppId(nativeMerchantDTO.getWechatMerchantId());
|
||||
upShopMerchant.setNativePayJson(JSONObject.toJSONString(nativeMerchantDTO));
|
||||
update(upShopMerchant, query().eq(ShopMerchant::getRelatedId, relatedId));
|
||||
}
|
||||
|
||||
@Cacheable(key = "#shopId")
|
||||
@Override
|
||||
public ShopMerchant getByShopId(Long shopId) {
|
||||
ShopMerchant shopMerchant = getOne(query().eq(ShopMerchant::getShopId, shopId));
|
||||
AssertUtil.isNull(shopMerchant, "暂未开通支付.");
|
||||
return shopMerchant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShopDirectMerchant getMainMerchant(Long shopId) {
|
||||
Long mainIdByShopId = shopInfoService.getMainIdByShopId(shopId);
|
||||
if (mainIdByShopId != null) {
|
||||
return shopDirectMerchantService.getOne(query().eq(ShopDirectMerchant::getShopId, mainIdByShopId));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
package com.czg.service.order.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
|
||||
import com.czg.account.entity.*;
|
||||
import com.czg.account.service.*;
|
||||
import com.czg.constants.PayTypeConstants;
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.enums.ShopUserFlowBizEnum;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.market.dto.MemberOrderDTO;
|
||||
import com.czg.market.entity.MemberOrder;
|
||||
import com.czg.market.entity.MkShopCouponRecord;
|
||||
import com.czg.market.service.MemberOrderService;
|
||||
import com.czg.market.service.MkShopCouponRecordService;
|
||||
import com.czg.market.service.MkShopRechargeService;
|
||||
import com.czg.market.vo.MkShopRechargeVO;
|
||||
import com.czg.order.dto.CheckOrderPay;
|
||||
import com.czg.order.dto.LtPayOtherDTO;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.order.entity.OrderPayment;
|
||||
import com.czg.order.service.OrderInfoCustomService;
|
||||
import com.czg.order.service.OrderPaymentService;
|
||||
import com.czg.pay.CzgPayBaseReq;
|
||||
import com.czg.pay.CzgRefundReq;
|
||||
import com.czg.pay.RefundRespDTO;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.order.dto.VipMemberPayParamDTO;
|
||||
import com.czg.service.order.dto.VipPayParamDTO;
|
||||
import com.czg.service.order.dto.VipRefundDTO;
|
||||
import com.czg.service.order.service.PayService;
|
||||
import com.czg.service.order.service.ShopUserPayService;
|
||||
import com.czg.utils.AssertUtil;
|
||||
import com.czg.utils.CzgRandomUtils;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
*/
|
||||
@Service
|
||||
public class ShopUserServiceImpl implements ShopUserPayService {
|
||||
@Resource
|
||||
private PayService payService;
|
||||
|
||||
@DubboReference
|
||||
private ShopUserService shopUserService;
|
||||
@DubboReference
|
||||
private UserInfoService userInfoService;
|
||||
@DubboReference
|
||||
private ShopInfoService shopInfoService;
|
||||
@DubboReference
|
||||
private FreeDineConfigService freeConfigService;
|
||||
@Resource
|
||||
private OrderInfoCustomService orderInfoCustomService;
|
||||
@DubboReference
|
||||
private MemberOrderService memberOrderService;
|
||||
@Resource
|
||||
private MkShopRechargeService shopRechargeService;
|
||||
@DubboReference
|
||||
private ShopUserFlowService userFlowService;
|
||||
@Resource
|
||||
private MkShopCouponRecordService recordService;
|
||||
@Resource
|
||||
private OrderPaymentService paymentService;
|
||||
|
||||
/**
|
||||
* 会员充值 校验
|
||||
*
|
||||
* @return 是否是霸王餐充值
|
||||
*/
|
||||
private boolean checkPayVip(VipPayParamDTO payParam) {
|
||||
if (payParam.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new CzgException("充值金额不正确");
|
||||
}
|
||||
if (payParam.getOrderId() != null) {
|
||||
FreeDineConfig freeConfig = freeConfigService.getById(shopInfoService.getMainIdByShopId(payParam.getShopId()));
|
||||
AssertUtil.isNull(freeConfig, "该店铺未启用霸王餐");
|
||||
if (!freeConfig.getEnable()) {
|
||||
throw new CzgException("该店铺未启用霸王餐");
|
||||
}
|
||||
CheckOrderPay checkOrderPay = payParam.getCheckOrderPay();
|
||||
OrderInfo orderInfo = orderInfoCustomService.checkOrderPay(checkOrderPay.setFreeDine(true).setWithCoupon(freeConfig.getWithCoupon()).setWithPoints(freeConfig.getWithPoints()));
|
||||
payParam.setAmount(orderInfo.getOrderAmount().multiply(BigDecimal.valueOf(freeConfig.getRechargeTimes())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Object> cashPayVip(VipPayParamDTO payParam) {
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
|
||||
AssertUtil.isNull(shopInfo, "店铺不存在");
|
||||
if (shopInfo.getIsMemberInPwd().equals(1)) {
|
||||
AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
|
||||
AssertUtil.isBlank(payParam.getPwd(), "请输入操作密码后充值");
|
||||
if (!shopInfo.getOperationPwd().equals(SecureUtil.md5(payParam.getPwd()))) {
|
||||
return CzgResult.failure("支付密码错误");
|
||||
}
|
||||
}
|
||||
// if (shopUser.getIsVip().equals(0)) {
|
||||
// //更新会员
|
||||
// ShopUser updateInfo = new ShopUser();
|
||||
// updateInfo.setIsVip(1);
|
||||
// updateInfo.setJoinTime(LocalDateTime.now());
|
||||
// updateInfo.setId(payParam.getShopUserId());
|
||||
// shopUserService.updateById(updateInfo);
|
||||
// }
|
||||
shopRechargeService.recharge(shopUser.getMainShopId(), shopUser.getId(), payParam.getRechargeDetailId(),
|
||||
payParam.getAmount(), null, "cash", ShopUserFlowBizEnum.CASH_IN, true);
|
||||
return CzgResult.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Map<String, Object>> jsPayVip(String clintIp, VipPayParamDTO payParam) {
|
||||
boolean isFree = checkPayVip(payParam);
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
String payOrderNo = payParam.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
|
||||
payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), payType, payOrderNo,
|
||||
payParam.getAmount(), "", isFree ? payParam.getOrderId() : payParam.getActivateId()));
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.JS_PAY,
|
||||
CzgPayBaseReq.jsPayReq(payOrderNo, "会员充值", payParam.getAmount().multiply(PayService.MONEY_RATE).longValue(),
|
||||
payParam.getPayType(), payParam.getOpenId(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CzgResult<Map<String, Object>> ltPayMember(String clientIp, VipMemberPayParamDTO payParam) {
|
||||
ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, shopInfoService.getMainIdByShopId(payParam.getShopId())).eq(ShopUser::getId, payParam.getShopUserId()));
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
MemberOrder memberOrder = memberOrderService.createMemberOrder(new MemberOrderDTO().setName(payParam.getName())
|
||||
.setNum(1).setNickName(payParam.getNickName()).setOrderType(payParam.getOrderType())
|
||||
.setPlatformType(payParam.getPlatformType()).setSex(payParam.getSex()).setUserId(shopUser.getUserId())
|
||||
.setShopId(payParam.getShopId()).setBirthDay(payParam.getBirthDay()));
|
||||
AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
|
||||
LtPayOtherDTO payParam1 = new LtPayOtherDTO()
|
||||
.setOpenId(payParam.getOpenId())
|
||||
.setPayType(payParam.getPayType())
|
||||
.setShopId(payParam.getShopId())
|
||||
.setRecordId(shopUser.getId())
|
||||
.setPrice(memberOrder.getAmount())
|
||||
.setIp(clientIp);
|
||||
return payService.ltPayOther(payParam1, PayTypeConstants.SourceType.MEMBER_PAY, "会员充值");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Map<String, Object>> ltPayVip(String clintIp, VipPayParamDTO payParam) {
|
||||
// 霸王餐校验
|
||||
boolean isFree = checkPayVip(payParam);
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
|
||||
AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
|
||||
|
||||
MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
|
||||
if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
|
||||
throw new CzgException("未开启自定义充值金额");
|
||||
}
|
||||
Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
|
||||
if (isFree) {
|
||||
BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
|
||||
payParam.setAmount(amount);
|
||||
}
|
||||
|
||||
String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
|
||||
LtPayOtherDTO payParam1 = new LtPayOtherDTO()
|
||||
.setOpenId(payParam.getOpenId())
|
||||
.setPayType(payParam.getPayType())
|
||||
.setShopId(payParam.getShopId())
|
||||
.setRecordId(shopUser.getId())
|
||||
.setPrice(payParam.getAmount())
|
||||
.setIp(clintIp);
|
||||
return payService.ltPayOther(payParam1, payType, "会员充值");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> recharge(String clientIp, VipPayParamDTO rechargeDTO, Long shopUserId) {
|
||||
boolean isFree = checkPayVip(rechargeDTO);
|
||||
Long mainShopId = shopInfoService.getMainIdByShopId(rechargeDTO.getShopId());
|
||||
|
||||
ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, mainShopId)
|
||||
.eq(ShopUser::getId, shopUserId));
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
MkShopRechargeVO rechargeVO = shopRechargeService.detail(rechargeDTO.getShopId());
|
||||
if (rechargeDTO.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
|
||||
throw new CzgException("未开启自定义充值金额");
|
||||
}
|
||||
UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
|
||||
BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, rechargeDTO.getShopId(), shopUser.getUserId(), rechargeDTO.getRechargeDetailId(), rechargeDTO.getAmount());
|
||||
String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
|
||||
|
||||
LtPayOtherDTO payParam = new LtPayOtherDTO()
|
||||
.setOpenId("wechatPay".equals(rechargeDTO.getPayType()) ? userInfo.getWechatOpenId() : userInfo.getAlipayOpenId())
|
||||
.setPayType(rechargeDTO.getPayType())
|
||||
.setShopId(rechargeDTO.getShopId())
|
||||
.setRecordId(shopUser.getId())
|
||||
.setPrice(amount)
|
||||
.setIp(clientIp);
|
||||
return payService.ltPayOther(payParam, payType, "会员充值");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Map<String, Object>> scanPayVip(String clintIp, VipPayParamDTO payParam) {
|
||||
boolean isFree = checkPayVip(payParam);
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
String payOrderNo = payParam.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
|
||||
payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), payType, payOrderNo,
|
||||
payParam.getAmount(), "", isFree ? payParam.getOrderId() : payParam.getActivateId()));
|
||||
return payService.pay(payParam.getShopId(), CzgPayEnum.SCAN_PAY,
|
||||
CzgPayBaseReq.scanPayReq(payOrderNo, "会员充值", payParam.getAmount().multiply(PayService.MONEY_RATE).longValue(), clintIp));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Map<String, Object>> microPayVip(VipPayParamDTO payParam) {
|
||||
boolean isFree = checkPayVip(payParam);
|
||||
AssertUtil.isBlank(payParam.getAuthCode(), "扫描码不能为空");
|
||||
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
|
||||
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
|
||||
String payOrderNo = payParam.getPlatformType() + CzgRandomUtils.snowflake();
|
||||
String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
|
||||
payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), payType, payOrderNo, payParam.getAmount(), "", isFree ? payParam.getOrderId() : payParam.getActivateId()));
|
||||
CzgResult<Map<String, Object>> mapCzgResult = payService.pay(payParam.getShopId(), CzgPayEnum.MICRO_PAY,
|
||||
CzgPayBaseReq.microPay(payOrderNo, "会员充值", payParam.getAmount().multiply(PayService.MONEY_RATE).longValue(), payParam.getAuthCode()));
|
||||
mapCzgResult.setData(Map.of("payOrderNo", payOrderNo));
|
||||
return mapCzgResult;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, BigDecimal>> refundVipBefore(VipRefundDTO payParam) {
|
||||
Map<String, BigDecimal> resultMap = new HashMap<>(5);
|
||||
ShopUser shopUser = shopUserService.getShopUserInfo(payParam.getShopId(), payParam.getUserId());
|
||||
AssertUtil.isNull(shopUser, "该店铺用户不存在");
|
||||
ShopUserFlow inFlow = userFlowService.getById(payParam.getFlowId());
|
||||
AssertUtil.isNull(inFlow, "充值记录不存在");
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(ShopUserFlow::getRelationId, payParam.getFlowId());
|
||||
queryWrapper.eq(ShopUserFlow::getBizCode, ShopUserFlowBizEnum.AWARD_IN.getCode());
|
||||
ShopUserFlow giftFlow = userFlowService.getOne(queryWrapper);
|
||||
resultMap.put("amount", shopUser.getAmount());
|
||||
resultMap.put("inAmount", inFlow.getAmount());
|
||||
resultMap.put("inRefundAmount", inFlow.getRefundAmount());
|
||||
resultMap.put("giftAmount", giftFlow == null ? BigDecimal.ZERO : giftFlow.getAmount());
|
||||
resultMap.put("giftRefundAmount", giftFlow == null ? BigDecimal.ZERO : giftFlow.getRefundAmount());
|
||||
return CzgResult.success(resultMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CzgResult<Object> refundVip(VipRefundDTO refPayParam) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(refPayParam.getShopId());
|
||||
if (shopInfo.getIsReturnPwd().equals(1)) {
|
||||
AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
|
||||
if (!SecureUtil.md5(refPayParam.getPwd()).equals(shopInfo.getOperationPwd())) {
|
||||
throw new CzgException("操作密码错误");
|
||||
}
|
||||
}
|
||||
ShopUser shopUser = shopUserService.getShopUserInfo(refPayParam.getShopId(), refPayParam.getUserId());
|
||||
ShopUserFlow inFlow = userFlowService.getById(refPayParam.getFlowId());
|
||||
AssertUtil.isNull(inFlow, "充值记录不存在");
|
||||
if ("cashIn".equals(inFlow.getBizCode()) || "adminIn".equals(inFlow.getBizCode())) {
|
||||
refPayParam.setCashRefund(true);
|
||||
}
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(ShopUserFlow::getRelationId, refPayParam.getFlowId());
|
||||
queryWrapper.eq(ShopUserFlow::getBizCode, ShopUserFlowBizEnum.AWARD_IN.getCode());
|
||||
ShopUserFlow giftFlow = userFlowService.getOne(queryWrapper);
|
||||
if ((inFlow.getAmount().subtract(inFlow.getRefundAmount())).compareTo(refPayParam.getRefAmount()) < 0) {
|
||||
return CzgResult.failure("退款失败,退款金额不可大于可退金额");
|
||||
}
|
||||
//用户余额减去赠送金额 小于 退款金额 则需要勾选 超额退款
|
||||
if (giftFlow != null) {
|
||||
if (shopUser.getAmount().subtract(giftFlow.getAmount().subtract(giftFlow.getRefundAmount())).compareTo(refPayParam.getRefAmount()) < 0 && !refPayParam.isOutOfRange()) {
|
||||
return CzgResult.failure("超额退款,请勾选 超额退款后重试");
|
||||
}
|
||||
} else {
|
||||
if (shopUser.getAmount().compareTo(refPayParam.getRefAmount()) < 0 && !refPayParam.isOutOfRange()) {
|
||||
return CzgResult.failure("超额退款,请勾选 超额退款后重试");
|
||||
}
|
||||
}
|
||||
Long refPaymentId = null;
|
||||
if (!refPayParam.isCashRefund()) {
|
||||
OrderPayment payment;
|
||||
if (inFlow.getRelationId() != null) {
|
||||
payment = paymentService.getById(inFlow.getRelationId());
|
||||
} else {
|
||||
return CzgResult.failure("退款失败,该充值记录不存在");
|
||||
}
|
||||
String refPayOrderNo = "REFVIP" + IdUtil.getSnowflakeNextId();
|
||||
refPaymentId = payService.initPayment(OrderPayment.refund(refPayParam.getShopId(), shopUser.getId(), PayTypeConstants.SourceType.MEMBER_IN,
|
||||
refPayOrderNo, refPayParam.getRefAmount(), inFlow.getId(), payment.getPlatformType()));
|
||||
CzgResult<RefundRespDTO> refund = payService.refund(refPayParam.getShopId(), new CzgRefundReq(refPayOrderNo, refPayParam.getRemark(),
|
||||
refPayParam.getRefAmount().multiply(PayService.MONEY_RATE).longValue(), payment.getAmount().multiply(PayService.MONEY_RATE).longValue(),
|
||||
payment.getOrderNo(), "", payment.getPlatformType()));
|
||||
if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getStatus())) {
|
||||
throw new CzgException(refund.getMsg());
|
||||
} else {
|
||||
paymentService.updateChain()
|
||||
.eq(OrderPayment::getId, refPaymentId)
|
||||
.set(OrderPayment::getPayTime, refund.getData().getRefundTime())
|
||||
.set(OrderPayment::getTradeNumber, refund.getData().getThirdRefundNo())
|
||||
.set(OrderPayment::getPayStatus, PayTypeConstants.PayStatus.SUCCESS)
|
||||
.set(OrderPayment::getRespJson, refund.getData().getOriginalData())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
|
||||
.setId(shopUser.getId())
|
||||
.setMoney(refPayParam.getRefAmount())
|
||||
.setType(0)
|
||||
.setRemark("退款")
|
||||
.setBizEnum(refPayParam.isCashRefund() ? ShopUserFlowBizEnum.RECHARGE_CASH_REFUND : ShopUserFlowBizEnum.RECHARGE_REFUND)
|
||||
.setRelationId(refPaymentId)
|
||||
.setRechargeId(inFlow.getId());
|
||||
//更新会员余额 并生成流水
|
||||
shopUserService.updateMoney(shopUserMoneyEditDTO);
|
||||
userFlowService.updateRefund(inFlow.getId(), refPayParam.getRefAmount());
|
||||
if (giftFlow != null && (giftFlow.getAmount().subtract(giftFlow.getRefundAmount())).compareTo(BigDecimal.ZERO) > 0) {
|
||||
ShopUserMoneyEditDTO giftFlowEdit = new ShopUserMoneyEditDTO()
|
||||
.setId(shopUser.getId())
|
||||
.setMoney(giftFlow.getAmount())
|
||||
.setType(0)
|
||||
.setRemark("退款")
|
||||
.setBizEnum(ShopUserFlowBizEnum.RECHARGE_REFUND)
|
||||
.setRelationId(refPaymentId)
|
||||
.setRechargeId(giftFlow.getId());
|
||||
//更新会员余额 并生成流水
|
||||
shopUserService.updateMoney(giftFlowEdit);
|
||||
userFlowService.updateRefund(giftFlow.getId(), giftFlow.getAmount());
|
||||
}
|
||||
//移除优惠券
|
||||
recordService.remove(QueryWrapper.create()
|
||||
.eq(MkShopCouponRecord::getSourceFlowId, inFlow.getId())
|
||||
.eq(MkShopCouponRecord::getSource, "activate")
|
||||
.eq(MkShopCouponRecord::getStatus, 0));
|
||||
return CzgResult.success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package com.czg.service.order.utils;
|
||||
|
||||
import cn.hutool.core.lang.func.Func0;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FunUtil {
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
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) {
|
||||
log.info("工具类开始执行函数");
|
||||
R result = function.get();
|
||||
boolean flag = check.apply(result);
|
||||
|
||||
log.info("执行结果: {}", result);
|
||||
|
||||
while (flag && retryCount-- > 0) {
|
||||
log.info("执行函数失败, 剩余尝试次数{}", retryCount);
|
||||
result = function.get();
|
||||
log.info("执行结果: {}", result);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,20 +6,23 @@
|
||||
|
||||
<insert id="createOrderDetails">
|
||||
INSERT INTO tb_order_detail(order_id, shop_id, product_id, product_img, product_name, product_type, sku_id,
|
||||
sku_name, price,member_price,discount_sale_amount,unit_price, discount_amount, pack_amount, pay_amount,
|
||||
sku_name, price,member_price,discount_sale_amount,unit_price, discount_amount,is_gift, pack_amount, pay_amount,
|
||||
return_amount, num, pack_number, coupon_num, is_time_discount,
|
||||
return_num, refund_num, refund_no, discount_sale_note, status, place_num, is_temporary, is_print, is_wait_call,
|
||||
pro_group_info, remark, refund_remark, create_time, update_time, is_urgent, sub_status, start_order_time, dish_out_time, food_serve_time, order_time)
|
||||
pro_group_info, remark, refund_remark, create_time, update_time, is_urgent, sub_status, start_order_time,
|
||||
dish_out_time, food_serve_time, order_time)
|
||||
VALUES
|
||||
<foreach collection="orderDetails" item="entity" separator=",">
|
||||
(#{orderId}, #{entity.shopId}, #{entity.productId}, #{entity.productImg}, #{entity.productName},
|
||||
#{entity.productType}, #{entity.skuId}, #{entity.skuName}, #{entity.price},#{entity.memberPrice},
|
||||
#{entity.discountSaleAmount}, #{entity.unitPrice}, #{entity.discountAmount},
|
||||
#{entity.discountSaleAmount}, #{entity.unitPrice}, #{entity.discountAmount},#{entity.isGift},
|
||||
#{entity.packAmount}, #{entity.payAmount}, #{entity.returnAmount}, #{entity.num}, #{entity.packNumber},
|
||||
#{entity.couponNum}, #{entity.isTimeDiscount}, #{entity.returnNum}, #{entity.refundNum}, #{entity.refundNo},
|
||||
#{entity.discountSaleNote}, #{entity.status}, #{entity.placeNum}, #{entity.isTemporary}, #{entity.isPrint},
|
||||
#{entity.isWaitCall}, #{entity.proGroupInfo}, #{entity.remark}, #{entity.refundRemark},
|
||||
now(), now(), #{entity.isUrgent}, #{entity.subStatus},#{entity.startOrderTime},#{entity.dishOutTime},#{entity.foodServeTime}, #{entity.orderTime})
|
||||
now(), now(), #{entity.isUrgent},
|
||||
#{entity.subStatus},#{entity.startOrderTime},#{entity.dishOutTime},#{entity.foodServeTime},
|
||||
#{entity.orderTime})
|
||||
</foreach>
|
||||
</insert>
|
||||
<select id="getOrderDetailPrint" resultType="com.czg.order.vo.OrderDetailPrintVo">
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.order.mapper.ShopDirectMerchantMapper">
|
||||
|
||||
<select id="getEntryList" resultType="com.czg.order.entity.ShopDirectMerchant">
|
||||
select merchant.*,shop.shop_name as shopName
|
||||
from tb_shop_direct_merchant merchant
|
||||
left join tb_shop_info shop on merchant.shop_id = shop.id
|
||||
<where>
|
||||
<if test="queryParam.userType != null">
|
||||
and merchant.user_type = #{queryParam.userType}
|
||||
</if>
|
||||
<if test="queryParam.shopName != null">
|
||||
and shop.shop_name like concat('%',#{queryParam.shopName},'%')
|
||||
</if>
|
||||
<if test="queryParam.status != null">
|
||||
and (merchant.wechat_status = #{queryParam.status} or merchant.alipay_status = #{queryParam.status})
|
||||
</if>
|
||||
<if test="queryParam.alipayAccount != null">
|
||||
and merchant.alipay_account like concat('%',#{queryParam.alipayAccount},'%')
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -2,6 +2,6 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.account.mapper.ShopMerchantMapper">
|
||||
<mapper namespace="com.czg.service.order.mapper.ShopMerchantMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -5,8 +5,9 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>cash-service</artifactId>
|
||||
<artifactId>cash</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>pay-service</artifactId>
|
||||
@@ -18,14 +19,19 @@
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.javen205</groupId>
|
||||
<artifactId>IJPay-All</artifactId>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>cash-common-tools</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>czg-pay</artifactId>
|
||||
<artifactId>poly-pay</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.czg</groupId>
|
||||
<artifactId>aggregation-pay</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.czg;
|
||||
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.pay.*;
|
||||
import com.czg.resp.CzgResult;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 支付适配器接口
|
||||
*
|
||||
* @author ww
|
||||
*
|
||||
*/
|
||||
public interface PayAdapter {
|
||||
|
||||
/**
|
||||
* 支付渠道
|
||||
* {@link com.czg.constant.PayChannelCst}
|
||||
*/
|
||||
String getChannel();
|
||||
|
||||
/**
|
||||
* 统一支付接口
|
||||
*
|
||||
* @param payType 支付类型
|
||||
* @param payData 支付数据 Json类型
|
||||
* 对应 聚合支付参数 {@link PolyMerchantDTO}
|
||||
* 对应 原生支付参数 {@link NativeMerchantDTO}
|
||||
* @param domain 域名 请求地址
|
||||
* @param notifyUrl 通知地址
|
||||
* @param bizData 业务数据
|
||||
*/
|
||||
CzgResult<Map<String, Object>> pay(@NonNull CzgPayEnum payType, @NotBlank String payData, @NotBlank String domain,
|
||||
@NotBlank String notifyUrl, CzgPayBaseReq bizData);
|
||||
|
||||
CzgResult<RefundRespDTO> refund(@NotBlank String domain, @NotBlank String payData, CzgRefundReq bizData);
|
||||
|
||||
CzgResult<QueryOrderRespDTO> queryPayOrder(@NotBlank String domain, @NotBlank String payData, String payOrderId, String mchOrderNo, String platform);
|
||||
|
||||
CzgResult<RefundRespDTO> queryRefund(@NotBlank String domain, @NotBlank String payData, String mchRefundNo, String refundOrderId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.czg;
|
||||
|
||||
import com.czg.constant.PayChannelCst;
|
||||
import com.czg.impl.NativePayAdapter;
|
||||
import com.czg.impl.PolyPayAdapter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 支付适配器工厂
|
||||
*
|
||||
* @author ww
|
||||
*/
|
||||
public class PayAdapterFactory {
|
||||
|
||||
private static final Map<String, PayAdapter> ADAPTER_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
ADAPTER_MAP.put(PayChannelCst.POLY, new PolyPayAdapter());
|
||||
ADAPTER_MAP.put(PayChannelCst.NATIVE, new NativePayAdapter());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取支付适配器
|
||||
*
|
||||
* @param channel 支付渠道,仅支持 {@link PayChannelCst}
|
||||
*/
|
||||
public static PayAdapter getAdapter(String channel) {
|
||||
PayAdapter adapter = ADAPTER_MAP.get(channel);
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException("支付渠道未注册适配器: " + channel);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.czg.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.PayAdapter;
|
||||
import com.czg.PayManager;
|
||||
import com.czg.constant.PayChannelCst;
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.pay.*;
|
||||
import com.czg.resp.CzgResult;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 原生支付适配器
|
||||
*
|
||||
* @author ww
|
||||
* @date 2023/10/20 14:20
|
||||
*/
|
||||
@Slf4j
|
||||
public class NativePayAdapter implements PayAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return PayChannelCst.NATIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> pay(@NonNull CzgPayEnum payType, String payData, String domain, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
try {
|
||||
NativeMerchantDTO merchantDTO = getMerchantDTO(payData);
|
||||
return switch (payType) {
|
||||
// case H5_PAY:
|
||||
// return h5Pay(merchantDTO, domain, notifyUrl, bizData);
|
||||
case JS_PAY -> jsPay(merchantDTO, notifyUrl, bizData);
|
||||
case LT_PAY -> jsPay(merchantDTO, notifyUrl, bizData);
|
||||
// case SCAN_PAY:
|
||||
// return scanPay(merchantDTO, domain, notifyUrl, bizData);
|
||||
case MICRO_PAY ->
|
||||
//扫码支付 扫描码
|
||||
barPay(merchantDTO, notifyUrl, bizData);
|
||||
default -> throw new CzgException("原生支付不支持该支付方式: " + bizData.getPayType());
|
||||
};
|
||||
} catch (Exception e) {
|
||||
log.error("聚合支付处理失败: {}", e.getMessage(), e);
|
||||
return CzgResult.failure("聚合支付处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<RefundRespDTO> refund(String domain, String payData, CzgRefundReq bizData) {
|
||||
NativeMerchantDTO merchantDTO = getMerchantDTO(payData);
|
||||
return CzgResult.success(PayManager.refund(bizData, bizData.getNotifyUrl(), merchantDTO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<QueryOrderRespDTO> queryPayOrder(String domain, String payData, String payOrderId, String mchOrderNo, String platform) {
|
||||
NativeMerchantDTO merchantDTO = getMerchantDTO(payData);
|
||||
QueryOrderRespDTO respDTO = PayManager.queryOrderStatus(platform, mchOrderNo, merchantDTO);
|
||||
return CzgResult.success(respDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<RefundRespDTO> queryRefund(String domain, String payData, String mchRefundNo, String refundOrderId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> jsPay(NativeMerchantDTO merchantDTO, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
bizData.setNotifyUrl(notifyUrl);
|
||||
return CzgResult.success(PayManager.jsapiPay(bizData, merchantDTO));
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> barPay(NativeMerchantDTO merchantDTO, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
bizData.setNotifyUrl(notifyUrl);
|
||||
return CzgResult.success(PayManager.barPay(bizData, merchantDTO));
|
||||
}
|
||||
|
||||
private NativeMerchantDTO getMerchantDTO(String payData) {
|
||||
return JSONObject.parseObject(payData, NativeMerchantDTO.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.czg.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.PayAdapter;
|
||||
import com.czg.PolyPayUtils;
|
||||
import com.czg.constant.PayChannelCst;
|
||||
import com.czg.constants.SystemConstants;
|
||||
import com.czg.entity.resp.CzgBaseResp;
|
||||
import com.czg.entity.resp.CzgRefundResp;
|
||||
import com.czg.enums.CzgPayEnum;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.pay.*;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.utils.AssertUtil;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
*/
|
||||
@Slf4j
|
||||
public class PolyPayAdapter implements PayAdapter {
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return PayChannelCst.POLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<Map<String, Object>> pay(@NonNull CzgPayEnum payType, @NotBlank String payData, @NotBlank String domain,
|
||||
@NotBlank String notifyUrl, CzgPayBaseReq bizData) {
|
||||
try {
|
||||
PolyMerchantDTO polyMerchantDTO = JSONObject.parseObject(payData, PolyMerchantDTO.class);
|
||||
return switch (payType) {
|
||||
case H5_PAY -> h5Pay(polyMerchantDTO, domain, notifyUrl, bizData);
|
||||
case JS_PAY -> jsPay(polyMerchantDTO, domain, notifyUrl, bizData);
|
||||
case LT_PAY -> ltPay(polyMerchantDTO, domain, notifyUrl, bizData);
|
||||
case SCAN_PAY -> scanPay(polyMerchantDTO, domain, notifyUrl, bizData);
|
||||
case MICRO_PAY -> microPay(polyMerchantDTO, domain, notifyUrl, bizData);
|
||||
default -> throw new CzgException("聚合支付不支持该支付方式: " + payType);
|
||||
};
|
||||
} catch (Exception e) {
|
||||
log.error("聚合支付处理失败: {}", e.getMessage(), e);
|
||||
return CzgResult.failure("聚合支付处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CzgResult<RefundRespDTO> refund(@NotBlank String domain, @NotBlank String payData, CzgRefundReq bizData) {
|
||||
PolyMerchantDTO shopMerchant = JSONObject.parseObject(payData, PolyMerchantDTO.class);
|
||||
CzgResult<CzgRefundResp> result = PolyPayUtils.refundOrder(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
|
||||
return convertRefundResp(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<QueryOrderRespDTO> queryPayOrder(@NotBlank String payData, @NotBlank String domain, String payOrderId, String mchOrderNo, String platform) {
|
||||
PolyMerchantDTO shopMerchant = JSONObject.parseObject(payData, PolyMerchantDTO.class);
|
||||
CzgResult<CzgBaseResp> result = PolyPayUtils.queryPayOrder(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), payOrderId, mchOrderNo);
|
||||
if (result.isSuccess()) {
|
||||
QueryOrderRespDTO respDTO = new QueryOrderRespDTO()
|
||||
.setStatus(result.getData().getState())
|
||||
.setOrderNo(result.getData().getMchOrderNo())
|
||||
.setAmount(result.getData().getAmount())
|
||||
.setErrorMsg("")
|
||||
.setOriginResp(JSONObject.toJSONString(result.getData()));
|
||||
return CzgResult.success(respDTO);
|
||||
}
|
||||
return CzgResult.failure(result.getMsg());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<RefundRespDTO> queryRefund(@NotBlank String payData, @NotBlank String domain, String mchRefundNo, String refundOrderId) {
|
||||
PolyMerchantDTO shopMerchant = JSONObject.parseObject(payData, PolyMerchantDTO.class);
|
||||
CzgResult<CzgRefundResp> result = PolyPayUtils.queryRefundOrder(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), mchRefundNo, refundOrderId);
|
||||
return convertRefundResp(result);
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> h5Pay(PolyMerchantDTO shopMerchant, String domain, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
bizData.polyBase(shopMerchant.getStoreId(), notifyUrl);
|
||||
return PolyPayUtils.h5Pay(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> jsPay(PolyMerchantDTO shopMerchant, String domain, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
AssertUtil.isBlank(bizData.getSubAppid(), "暂不可用,请联系商家配置" + (SystemConstants.PayType.ALIPAY.equals(bizData.getPayType()) ? "支付宝" : "微信") + "小程序");
|
||||
bizData.setPayType(SystemConstants.PayType.ALIPAY.equals(bizData.getPayType()) ? "ALIPAY" : "WECHAT");
|
||||
bizData.polyBase(shopMerchant.getStoreId(), notifyUrl);
|
||||
return PolyPayUtils.jsPay(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
|
||||
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> ltPay(PolyMerchantDTO shopMerchant, String domain, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
AssertUtil.isBlank(bizData.getSubAppid(), "暂不可用,请联系商家配置" + ("aliPay".equals(bizData.getPayType()) ? "支付宝" : "微信") + "小程序");
|
||||
bizData.polyBase(shopMerchant.getStoreId(), notifyUrl);
|
||||
return PolyPayUtils.ltPay(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> scanPay(PolyMerchantDTO shopMerchant, String domain, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
bizData.polyBase(shopMerchant.getStoreId(), notifyUrl);
|
||||
return PolyPayUtils.scanPay(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
|
||||
}
|
||||
|
||||
private CzgResult<Map<String, Object>> microPay(PolyMerchantDTO shopMerchant, String domain, String notifyUrl, CzgPayBaseReq bizData) {
|
||||
bizData.polyBase(shopMerchant.getStoreId(), notifyUrl);
|
||||
return PolyPayUtils.microPay(domain, shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
|
||||
}
|
||||
|
||||
private CzgResult<RefundRespDTO> convertRefundResp(CzgResult<CzgRefundResp> result) {
|
||||
if (result.isSuccess()) {
|
||||
RefundRespDTO respDTO = new RefundRespDTO()
|
||||
.setStatus(result.getData().getState())
|
||||
.setMerchantRefundNo(result.getData().getMchRefundNo())
|
||||
.setThirdRefundNo(result.getData().getRefundOrderId())
|
||||
.setPlatform(result.getData().getPayType())
|
||||
.setRefundAmount(result.getData().getRefundAmt())
|
||||
.setRefundTime(result.getData().getRefundTime())
|
||||
.setOriginalData(result.getData().getExtParam());
|
||||
return CzgResult.success(respDTO);
|
||||
}
|
||||
|
||||
return CzgResult.failure(result.getMsg());
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.czg.service;
|
||||
|
||||
import com.czg.entity.notify.CzgPayNotifyDTO;
|
||||
import com.czg.entity.notify.CzgRefundNotifyDTO;
|
||||
import com.czg.entity.req.*;
|
||||
import com.czg.entity.resp.*;
|
||||
import com.czg.resp.CzgResult;
|
||||
import lombok.NonNull;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
* @description
|
||||
*/
|
||||
public interface CzgPayService {
|
||||
/**
|
||||
* h5支付
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
*/
|
||||
CzgResult<CzgH5PayResp> h5Pay(@NonNull String appId, @NonNull String appSecret, CzgH5PayReq bizData);
|
||||
|
||||
/**
|
||||
* js支付
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
*/
|
||||
CzgResult<CzgJsPayResp> jsPay(@NonNull String appId, @NonNull String appSecret, CzgJsPayReq bizData);
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
*/
|
||||
CzgResult<CzgLtPayResp> ltPay(@NonNull String appId, @NonNull String appSecret, CzgLtPayReq bizData);
|
||||
|
||||
/**
|
||||
* PC扫码支付
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
*/
|
||||
CzgResult<CzgScanPayResp> scanPay(@NonNull String appId, @NonNull String appSecret, CzgScanPayReq bizData);
|
||||
|
||||
/**
|
||||
* 聚合反扫
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
*/
|
||||
CzgResult<CzgMicroPayResp> microPay(@NonNull String appId, @NonNull String appSecret, CzgMicroPayReq bizData);
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
* @param payOrderId 平台订单号
|
||||
* @param mchOrderNo 商户订单号
|
||||
*/
|
||||
CzgResult<CzgBaseResp> queryPayOrder(@NonNull String appId, @NonNull String appSecret,
|
||||
String payOrderId, String mchOrderNo);
|
||||
|
||||
|
||||
/**
|
||||
* 订单退款
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
*/
|
||||
CzgResult<CzgRefundResp> refundOrder(@NonNull String appId, @NonNull String appSecret, CzgRefundReq bizData);
|
||||
|
||||
/**
|
||||
* 退款订单查询
|
||||
*
|
||||
* @param appId 应用id tb_shop_merchant 表中的 app_id
|
||||
* @param appSecret 应用密钥 tb_shop_merchant 表中的 app_secret
|
||||
* @param mchRefundNo 商户退款订单号 二选一
|
||||
* @param refundOrderId 平台退款订单号 二选一
|
||||
*/
|
||||
CzgResult<CzgRefundResp> queryRefundOrder(@NonNull String appId, @NonNull String appSecret,
|
||||
String mchRefundNo, String refundOrderId);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package com.czg.service.Impl;
|
||||
|
||||
import com.czg.CzgPayUtils;
|
||||
import com.czg.constants.ParamCodeCst;
|
||||
import com.czg.entity.req.*;
|
||||
import com.czg.entity.resp.*;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.CzgPayService;
|
||||
import com.czg.system.service.SysParamsService;
|
||||
import lombok.NonNull;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author ww
|
||||
* @description 1
|
||||
*/
|
||||
@Service
|
||||
public class CzgPayServiceImpl implements CzgPayService {
|
||||
|
||||
@DubboReference
|
||||
private SysParamsService sysParamsService;
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgH5PayResp> h5Pay(@NonNull String appId, @NonNull String appSecret, CzgH5PayReq bizData) {
|
||||
return CzgPayUtils.h5Pay(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, bizData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgJsPayResp> jsPay(@NonNull String appId, @NonNull String appSecret, CzgJsPayReq bizData) {
|
||||
return CzgPayUtils.jsPay(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, bizData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgLtPayResp> ltPay(@NonNull String appId, @NonNull String appSecret, CzgLtPayReq bizData) {
|
||||
return CzgPayUtils.ltPay(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, bizData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgScanPayResp> scanPay(@NonNull String appId, @NonNull String appSecret, CzgScanPayReq bizData) {
|
||||
return CzgPayUtils.scanPay(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, bizData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgMicroPayResp> microPay(@NonNull String appId, @NonNull String appSecret, CzgMicroPayReq bizData) {
|
||||
return CzgPayUtils.microPay(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, bizData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgBaseResp> queryPayOrder(@NonNull String appId, @NonNull String appSecret, String payOrderId, String mchOrderNo) {
|
||||
return CzgPayUtils.queryPayOrder(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, payOrderId, mchOrderNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgRefundResp> refundOrder(@NonNull String appId, @NonNull String appSecret, CzgRefundReq bizData) {
|
||||
return CzgPayUtils.refundOrder(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, bizData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CzgResult<CzgRefundResp> queryRefundOrder(@NonNull String appId, @NonNull String appSecret, String mchRefundNo, String refundOrderId) {
|
||||
return CzgPayUtils.queryRefundOrder(sysParamsService.getSysParamValue(ParamCodeCst.System.PAY_CZG_DOMAIN), appId, appSecret, mchRefundNo, refundOrderId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
<module>product-service</module>
|
||||
<module>system-service</module>
|
||||
<module>code-generator</module>
|
||||
<module>pay-service</module>
|
||||
<module>market-service</module>
|
||||
</modules>
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.czg.product.entity.Product;
|
||||
import com.czg.product.entity.ProductStockFlow;
|
||||
import com.czg.product.service.ProductStockFlowService;
|
||||
import com.czg.sa.StpKit;
|
||||
import com.czg.service.product.mapper.ConsInfoMapper;
|
||||
import com.czg.service.product.mapper.ProductMapper;
|
||||
import com.czg.service.product.mapper.ProductStockFlowMapper;
|
||||
@@ -44,15 +43,7 @@ public class ProductStockFlowServiceImpl extends ServiceImpl<ProductStockFlowMap
|
||||
Long shopId = entity.getShopId();
|
||||
BigDecimal afterNumber = entity.getAfterNumber();
|
||||
Product product = productMapper.selectOneById(entity.getProductId());
|
||||
String shopName = "";
|
||||
try {
|
||||
shopName = StpKit.USER.getShopName();
|
||||
} catch (Exception e) {
|
||||
log.error("获取店铺名称失败");
|
||||
}
|
||||
if (StrUtil.isEmpty(shopName)) {
|
||||
shopName = productMapper.getShopName(shopId);
|
||||
}
|
||||
String shopName = productMapper.getShopName(shopId);
|
||||
BigDecimal warnLine = Convert.toBigDecimal(product.getWarnLine());
|
||||
// 库存小于警告值,发送消息提醒
|
||||
if (NumberUtil.isLess(afterNumber, warnLine)) {
|
||||
|
||||
@@ -153,6 +153,10 @@
|
||||
<foreach item="item" collection="idList" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
or t1.sync_id in
|
||||
<foreach item="item" collection="idList" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
</if>
|
||||
order by t1.sort desc,t1.id desc
|
||||
</select>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.czg.service.system.mapper;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.czg.system.entity.SysBankInfo;
|
||||
|
||||
/**
|
||||
* 银行账户信息表 映射层。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-06
|
||||
*/
|
||||
public interface SysBankInfoMapper extends BaseMapper<SysBankInfo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.czg.service.system.mapper;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.czg.system.entity.SysCategoryInfo;
|
||||
|
||||
/**
|
||||
* 类目信息表 映射层。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-06
|
||||
*/
|
||||
public interface SysCategoryInfoMapper extends BaseMapper<SysCategoryInfo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.czg.service.system.mapper;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.czg.system.entity.SysRegion;
|
||||
|
||||
/**
|
||||
* 行政区表 映射层。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-06
|
||||
*/
|
||||
public interface SysRegionMapper extends BaseMapper<SysRegion> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.czg.service.system.service.impl;
|
||||
|
||||
import com.czg.BaseQueryParam;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import com.czg.system.entity.SysBankInfo;
|
||||
import com.czg.system.service.SysBankInfoService;
|
||||
import com.czg.service.system.mapper.SysBankInfoMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 银行账户信息表 服务层实现。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-06
|
||||
*/
|
||||
@Service
|
||||
public class SysBankInfoServiceImpl extends ServiceImpl<SysBankInfoMapper, SysBankInfo> implements SysBankInfoService {
|
||||
|
||||
@Override
|
||||
public Page<SysBankInfo> bankInfoList(BaseQueryParam param, String bankName) {
|
||||
return page(Page.of(param.getPage(), param.getSize()), query().like(SysBankInfo::getBankAlias, bankName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.czg.service.system.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.czg.system.vo.SysCategoryInfoVO;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import com.czg.system.entity.SysCategoryInfo;
|
||||
import com.czg.system.service.SysCategoryInfoService;
|
||||
import com.czg.service.system.mapper.SysCategoryInfoMapper;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 类目信息表 服务层实现。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-06
|
||||
*/
|
||||
@Service
|
||||
public class SysCategoryInfoServiceImpl extends ServiceImpl<SysCategoryInfoMapper, SysCategoryInfo> implements SysCategoryInfoService {
|
||||
|
||||
@Cacheable(value = "common:category", key = "'all'")
|
||||
@Override
|
||||
public List<SysCategoryInfoVO> categoryList() {
|
||||
List<SysCategoryInfo> list = list();
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return List.of();
|
||||
}
|
||||
List<SysCategoryInfoVO> result = new ArrayList<>();
|
||||
Map<String, List<SysCategoryInfo>> stringListMap = CollStreamUtil.groupByKey(list, SysCategoryInfo::getFirstCategory);
|
||||
stringListMap.forEach((k, v) -> {
|
||||
SysCategoryInfoVO vo = new SysCategoryInfoVO();
|
||||
vo.setFirstCategory(k);
|
||||
vo.setChild(v);
|
||||
result.add(vo);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.czg.service.system.service.impl;
|
||||
|
||||
import com.czg.service.system.mapper.SysRegionMapper;
|
||||
import com.czg.system.entity.SysRegion;
|
||||
import com.czg.system.service.SysRegionService;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 行政区表 服务层实现。
|
||||
*
|
||||
* @author ww
|
||||
* @since 2026-01-06
|
||||
*/
|
||||
@Service
|
||||
public class SysRegionServiceImpl extends ServiceImpl<SysRegionMapper, SysRegion> implements SysRegionService {
|
||||
|
||||
|
||||
@Cacheable(value = "common:region", key = "'all'")
|
||||
@Override
|
||||
public List<SysRegion> regionList() {
|
||||
// 1. 单次查询获取所有数据
|
||||
List<SysRegion> allRegions = list(query().ne(SysRegion::getRegionLevel, 1));
|
||||
// 2. 一次性按层级分组,减少流遍历次数
|
||||
Map<Integer, List<SysRegion>> regionByLevel = allRegions.stream()
|
||||
.collect(Collectors.groupingBy(SysRegion::getRegionLevel));
|
||||
|
||||
// 3. 获取各层级数据,默认空列表避免空指针
|
||||
List<SysRegion> parents = regionByLevel.getOrDefault(2, List.of());
|
||||
List<SysRegion> level3Regions = regionByLevel.getOrDefault(3, List.of());
|
||||
List<SysRegion> level4Regions = regionByLevel.getOrDefault(4, List.of());
|
||||
|
||||
// 4. 构建3级地区的子节点映射(4级),使用HashMap保证性能
|
||||
Map<String, List<SysRegion>> level4ByParentId = level4Regions.stream()
|
||||
.collect(Collectors.groupingBy(SysRegion::getParentRegionId, Collectors.toList()));
|
||||
|
||||
level3Regions.forEach(level3 -> {
|
||||
List<SysRegion> children = level4ByParentId.getOrDefault(level3.getRegionId(), List.of());
|
||||
level3.setChildren(children);
|
||||
});
|
||||
|
||||
Map<String, List<SysRegion>> level3ByParentId = level3Regions.stream()
|
||||
.collect(Collectors.groupingBy(SysRegion::getParentRegionId));
|
||||
|
||||
parents.forEach(parent -> {
|
||||
List<SysRegion> children = level3ByParentId.getOrDefault(parent.getRegionId(), List.of());
|
||||
parent.setChildren(children);
|
||||
});
|
||||
return parents;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.system.mapper.SysBankInfoMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.system.mapper.SysCategoryInfoMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.system.mapper.SysRegionMapper">
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user