|
@@ -3,9 +3,10 @@ package com.fs.his.service.impl;
|
|
|
import java.lang.reflect.Field;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
|
-import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
|
@@ -17,8 +18,6 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.fs.common.annotation.DataScope;
|
|
|
-import com.fs.common.annotation.Log;
|
|
|
-import com.fs.common.core.domain.AjaxResult;
|
|
|
import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
import com.fs.common.exception.CustomException;
|
|
@@ -26,7 +25,6 @@ import com.fs.common.utils.DateUtils;
|
|
|
import com.fs.common.utils.ServletUtils;
|
|
|
import com.fs.common.utils.StringUtils;
|
|
|
import com.fs.common.utils.ip.IpUtils;
|
|
|
-import com.fs.common.utils.poi.ExcelUtil;
|
|
|
import com.fs.company.domain.Company;
|
|
|
import com.fs.company.domain.CompanyUser;
|
|
|
import com.fs.company.mapper.CompanyConfigMapper;
|
|
@@ -39,19 +37,15 @@ import com.fs.config.cloud.CloudHostProper;
|
|
|
import com.fs.core.config.WxMaConfiguration;
|
|
|
import com.fs.core.config.WxPayProperties;
|
|
|
import com.fs.core.utils.OrderCodeUtils;
|
|
|
-import com.fs.course.config.CourseConfig;
|
|
|
import com.fs.course.config.RedPacketConfig;
|
|
|
import com.fs.course.domain.FsCourseRedPacketLog;
|
|
|
-import com.fs.course.mapper.FsCourseRedPacketLogMapper;
|
|
|
import com.fs.course.service.IFsCourseRedPacketLogService;
|
|
|
import com.fs.course.service.IFsUserCourseOrderService;
|
|
|
import com.fs.course.service.IFsUserVipOrderService;
|
|
|
-import com.fs.erp.dto.ErpRefundUpdateRequest;
|
|
|
import com.fs.his.domain.*;
|
|
|
import com.fs.his.dto.PayConfigDTO;
|
|
|
import com.fs.his.enums.PaymentMethodEnum;
|
|
|
import com.fs.his.mapper.*;
|
|
|
-import com.fs.his.param.FsStoreOrderParam;
|
|
|
import com.fs.his.param.FsStorePaymentParam;
|
|
|
import com.fs.his.param.PayOrderParam;
|
|
|
import com.fs.his.param.WxSendRedPacketParam;
|
|
@@ -77,7 +71,6 @@ import com.fs.system.oss.CloudStorageService;
|
|
|
import com.fs.system.oss.OSSFactory;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.tzBankPay.TzBankService.TzBankService;
|
|
|
-import com.fs.tzBankPay.TzBankService.TzBankServiceImpl.TzBankServiceImpl;
|
|
|
import com.fs.tzBankPay.doman.*;
|
|
|
import com.fs.ybPay.domain.CreateWxOrderResult;
|
|
|
import com.fs.ybPay.domain.OrderResult;
|
|
@@ -85,45 +78,35 @@ import com.fs.ybPay.dto.OrderQueryDTO;
|
|
|
import com.fs.ybPay.dto.RefundDTO;
|
|
|
import com.fs.ybPay.dto.WxJspayDTO;
|
|
|
import com.fs.ybPay.service.IPayService;
|
|
|
-import com.github.binarywang.wxpay.bean.merchanttransfer.TransferCreateRequest;
|
|
|
-import com.github.binarywang.wxpay.bean.merchanttransfer.TransferCreateResult;
|
|
|
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
|
|
|
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
|
|
|
import com.github.binarywang.wxpay.bean.notify.WxPayTransferBatchesNotifyV3Result;
|
|
|
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
|
|
|
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
|
|
|
-import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
|
|
|
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
|
|
|
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
|
|
|
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
|
|
|
import com.github.binarywang.wxpay.bean.transfer.*;
|
|
|
import com.github.binarywang.wxpay.config.WxPayConfig;
|
|
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
|
|
-import com.github.binarywang.wxpay.service.MerchantTransferService;
|
|
|
-import com.github.binarywang.wxpay.service.RedpackService;
|
|
|
import com.github.binarywang.wxpay.service.TransferService;
|
|
|
import com.github.binarywang.wxpay.service.WxPayService;
|
|
|
-import com.github.binarywang.wxpay.service.impl.RedpackServiceImpl;
|
|
|
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
|
|
import com.google.gson.Gson;
|
|
|
import com.hc.openapi.tool.fastjson.JSON;
|
|
|
-import com.wechat.pay.java.service.transferbatch.TransferBatchService;
|
|
|
-import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
|
|
|
-import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
|
|
import me.chanjar.weixin.common.error.WxErrorException;
|
|
|
-import me.chanjar.weixin.mp.api.WxMpService;
|
|
|
import org.apache.commons.lang.exception.ExceptionUtils;
|
|
|
-import org.apache.hc.core5.concurrent.CompletedFuture;
|
|
|
import org.redisson.api.RLock;
|
|
|
import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.aop.framework.AopContext;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
|
-import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Propagation;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
@@ -137,6 +120,7 @@ import javax.servlet.http.HttpServletRequest;
|
|
|
* @date 2023-08-11
|
|
|
*/
|
|
|
@Service
|
|
|
+@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
|
|
|
public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
Logger logger = LoggerFactory.getLogger(getClass());
|
|
|
@Autowired
|
|
@@ -207,10 +191,23 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
@Value("${enableRedPackAccount:0}")
|
|
|
private String ENABLE_RED_PACK_ACCOUNT;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private ICompanyConfigService companyConfigService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedissonClient redissonClient;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedPacketLogMapper redPacketLogMapper;
|
|
|
+
|
|
|
/**
|
|
|
* 红包账户锁
|
|
|
*/
|
|
|
private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
|
|
|
+ /**
|
|
|
+ * 红包锁
|
|
|
+ */
|
|
|
+ private static final String REDPACKET_LOCK = "redpacket_lock:%d";
|
|
|
|
|
|
/**
|
|
|
* 公司红包金额
|
|
@@ -222,6 +219,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
*/
|
|
|
private static final String REDPACKET_USER_LIMIT = "redpacket_user_limit:%s:%d";
|
|
|
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 查询支付明细
|
|
|
*
|
|
@@ -525,18 +524,111 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
return fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
|
|
|
}
|
|
|
|
|
|
- @Autowired
|
|
|
- private ICompanyConfigService companyConfigService;
|
|
|
|
|
|
- @Autowired
|
|
|
- private RedissonClient redissonClient;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private RedPacketLogMapper redPacketLogMapper;
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
|
|
|
public R sendRedPacket(WxSendRedPacketParam param) {
|
|
|
+ IFsStorePaymentService service = (IFsStorePaymentService) AopContext.currentProxy();
|
|
|
+
|
|
|
+ if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
|
|
|
+ return service.sendRedPacketDeduction(param);
|
|
|
+ } else {
|
|
|
+ return service.sendRedPacketLimit(param);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R sendRedPacketLimit(WxSendRedPacketParam param){
|
|
|
+ FsUser user = param.getUser();
|
|
|
+
|
|
|
+ if(user == null) {
|
|
|
+ throw new IllegalArgumentException("[发送红包] 用户id为必传参数!");
|
|
|
+ }
|
|
|
+ Long userId = user.getUserId();
|
|
|
|
|
|
+ String key = String.format(REDPACKET_LOCK,userId);
|
|
|
+ RLock lock = redissonClient.getLock(key);
|
|
|
+
|
|
|
+ try{
|
|
|
+ boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ if (!locked) {
|
|
|
+ logger.error("获取锁失败");
|
|
|
+ return R.error("[红包领取] 系统繁忙,请重试!");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 判断当前用户是否限流
|
|
|
+ String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
|
|
+ String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, userId);
|
|
|
+ Integer userCount = redisTemplateInteger.opsForValue().get(userLimitKey);
|
|
|
+
|
|
|
+
|
|
|
+ // 首次领取
|
|
|
+ if(userCount == null) {
|
|
|
+ userCount = 0;
|
|
|
+ long expireSeconds = getExpireSeconds();
|
|
|
+ redisTemplateInteger.opsForValue().set(userLimitKey, userCount, expireSeconds, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(userCount >= RED_PACKET_LIMIT_COUNT){
|
|
|
+ logger.info("[红包领取] 用户{} 领取红包已经达到最大限制!",userId);
|
|
|
+ return R.error("[红包领取] 当前用户当前已经领取红包已经达到限制!");
|
|
|
+ }
|
|
|
+
|
|
|
+ String json;
|
|
|
+ RedPacketConfig config = new RedPacketConfig();
|
|
|
+ // 根据红包模式获取配置
|
|
|
+ switch (param.getRedPacketMode()){
|
|
|
+ case 1:
|
|
|
+ json = configService.selectConfigByKey("redPacket.config");
|
|
|
+ config = JSONUtil.toBean(json, RedPacketConfig.class);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
|
|
|
+ config = JSONUtil.toBean(json, RedPacketConfig.class);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new UnsupportedOperationException("当前红包模式不支持!");
|
|
|
+ }
|
|
|
+ //H5的用公众号的appid发,小程序的用小程序的appid来发
|
|
|
+ if (param.getSource()==2){
|
|
|
+ // 传参appId为空时,仍然使用配置里面的
|
|
|
+ String appId = StringUtils.isBlank(param.getAppId()) ? config.getMiniappId() : param.getAppId();
|
|
|
+ config.setAppId(appId);
|
|
|
+ }
|
|
|
+ logger.info("最终传参 {}",config);
|
|
|
+ //组合返回参数
|
|
|
+ R result = new R();
|
|
|
+ // 根据 isNew 判断使用哪种发红包方式
|
|
|
+ if (config.getIsNew() != null && config.getIsNew() == 1) {
|
|
|
+ result = sendRedPacketV3Internal(param, config);
|
|
|
+ } else {
|
|
|
+ result= sendRedPacketLegacyInternal(param, config);
|
|
|
+ }
|
|
|
+ result.put("mchId", config.getMchId());
|
|
|
+ result.put("isNew",config.getIsNew());
|
|
|
+ logger.info("红包返回:{}",result);
|
|
|
+
|
|
|
+ // 用户领取红包次数+1
|
|
|
+ redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
|
|
|
+ return result;
|
|
|
+ }catch (Exception e){
|
|
|
+ logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }finally {
|
|
|
+ if (lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 开启红包账户扣减-发红包
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R sendRedPacketDeduction(WxSendRedPacketParam param){
|
|
|
//---------------发红包前先判断润天账户余额是否足够---------
|
|
|
RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
|
|
|
RedPacketLog redPacketLog = null;
|
|
@@ -558,8 +650,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
Long userId = user.getUserId();
|
|
|
|
|
|
// 判断当前用户是否限流
|
|
|
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
|
|
- String today = sdf.format(new Date());
|
|
|
+ String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
|
|
String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, userId);
|
|
|
Integer userCount = redisTemplateInteger.opsForValue().get(userLimitKey);
|
|
|
|
|
@@ -577,37 +668,33 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
}
|
|
|
|
|
|
|
|
|
- BigDecimal companyMoney = null;
|
|
|
-
|
|
|
- if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
|
|
|
- companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
|
|
|
-
|
|
|
- if(ObjectUtils.isNull(companyMoney)){
|
|
|
- SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
|
|
|
- if(ObjectUtils.isNull(sysConfig)){
|
|
|
- throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
|
|
|
- }
|
|
|
- String configValue = sysConfig.getConfigValue();
|
|
|
- companyMoney = new BigDecimal(configValue);
|
|
|
- logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
|
|
|
- }
|
|
|
+ BigDecimal companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
|
|
|
|
|
|
- if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
- logger.info("润天账户余额: {} 不足!", companyMoney);
|
|
|
- return R.error("[红包领取] 账户余额不足,请联系管理员!");
|
|
|
+ if(ObjectUtils.isNull(companyMoney)){
|
|
|
+ SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
|
|
|
+ if(ObjectUtils.isNull(sysConfig)){
|
|
|
+ throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
|
|
|
}
|
|
|
+ String configValue = sysConfig.getConfigValue();
|
|
|
+ companyMoney = new BigDecimal(configValue);
|
|
|
+ logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
|
|
|
+ }
|
|
|
|
|
|
- redPacketLog = new RedPacketLog();
|
|
|
- redPacketLog.setRedPacketMode(param.getRedPacketMode());
|
|
|
- redPacketLog.setAmount(param.getAmount());
|
|
|
- redPacketLog.setAppId(param.getAppId());
|
|
|
- redPacketLog.setCompanyId(param.getCompanyId());
|
|
|
- redPacketLog.setCreateTime(LocalDateTime.now());
|
|
|
- redPacketLog.setUserId(userId);
|
|
|
- redPacketLog.setAccBalanceBefore(companyMoney);
|
|
|
- redPacketLog.setSource(param.getSource());
|
|
|
+ if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ logger.info("润天账户余额: {} 不足!", companyMoney);
|
|
|
+ return R.error("[红包领取] 账户余额不足,请联系管理员!");
|
|
|
}
|
|
|
|
|
|
+ redPacketLog = new RedPacketLog();
|
|
|
+ redPacketLog.setRedPacketMode(param.getRedPacketMode());
|
|
|
+ redPacketLog.setAmount(param.getAmount());
|
|
|
+ redPacketLog.setAppId(param.getAppId());
|
|
|
+ redPacketLog.setCompanyId(param.getCompanyId());
|
|
|
+ redPacketLog.setCreateTime(LocalDateTime.now());
|
|
|
+ redPacketLog.setUserId(userId);
|
|
|
+ redPacketLog.setAccBalanceBefore(companyMoney);
|
|
|
+ redPacketLog.setSource(param.getSource());
|
|
|
+
|
|
|
String json;
|
|
|
RedPacketConfig config = new RedPacketConfig();
|
|
|
// 根据红包模式获取配置
|
|
@@ -620,6 +707,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
|
|
|
config = JSONUtil.toBean(json, RedPacketConfig.class);
|
|
|
break;
|
|
|
+ default:
|
|
|
+ throw new UnsupportedOperationException("当前红包模式不支持!");
|
|
|
}
|
|
|
//H5的用公众号的appid发,小程序的用小程序的appid来发
|
|
|
if (param.getSource()==2){
|
|
@@ -640,20 +729,17 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
result.put("isNew",config.getIsNew());
|
|
|
logger.info("红包返回:{}",result);
|
|
|
|
|
|
+ // 更新账户余额
|
|
|
+ logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
|
|
|
|
|
|
- if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
|
|
|
- // 更新账户余额
|
|
|
- logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
|
|
|
+ companyMoney = companyMoney.subtract(amount);
|
|
|
+ redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
|
|
|
|
|
|
- companyMoney = companyMoney.subtract(amount);
|
|
|
- redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
|
|
|
+ redPacketLog.setAccBalanceAfter(companyMoney);
|
|
|
+ redPacketLog.setUpdateTime(LocalDateTime.now());
|
|
|
+ redPacketLog.setStatus(1);
|
|
|
|
|
|
|
|
|
- redPacketLog.setAccBalanceAfter(companyMoney);
|
|
|
- redPacketLog.setUpdateTime(LocalDateTime.now());
|
|
|
- redPacketLog.setStatus(1);
|
|
|
- }
|
|
|
-
|
|
|
// 用户领取红包次数+1
|
|
|
redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
|
|
|
|
|
@@ -1386,8 +1472,6 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
@Override
|
|
|
public R paymentByWxaCode(FsStorePaymentPayParam param) {
|
|
|
FsUser user = userMapper.selectFsUserById(param.getUserId());
|