Explorar el Código

fix 支付宝红包转账

zoujiajian hace 3 años
padre
commit
a57b852b23

+ 27 - 0
netflix-common/src/main/java/com/cyksj/common/constant/TransferConstant.java

@@ -0,0 +1,27 @@
+package com.cyksj.common.constant;
+
+/*
+ *项目名: netflix
+ *文件名: TransferConstant
+ *创建者: JavaZou
+ *创建时间:2023/2/28 12:03
+ */
+public interface TransferConstant {
+
+	String ALIPAY = "alipay";
+
+	String WECHAT_PAY = "wechat";
+
+	/**
+	 * biz_scene
+	 * DIRECT_TRANSFER:单笔无密转账到支付宝,B2C现金红包;
+	 * PERSONAL_COLLECTION:C2C现金红包-领红包
+	 */
+	String DIRECT_TRANSFER = "DIRECT_TRANSFER";
+
+	String PERSONAL_COLLECTION = "PERSONAL_COLLECTION";
+
+	String RED_PACKET = "REDPACKET";
+
+	String ALIPAY_LOGON_ID = "ALIPAY_LOGON_ID";
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/TransferAccountsRecordMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.TransferAccountsRecord;
+
+/*
+ *项目名: netflix
+ *文件名: TransferAccountsRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/2/28 11:42
+ */
+public interface TransferAccountsRecordMapper extends BaseMapper<TransferAccountsRecord> {
+}

+ 68 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/TransferAccountsRecord.java

@@ -0,0 +1,68 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: TransferAccountsRecord
+ *创建者: JavaZou
+ *创建时间:2023/2/28 11:36
+ */
+@Getter
+@Setter
+public class TransferAccountsRecord extends BaseEntity{
+	private Long userId;
+
+	/**
+	 * 商户转账订单号
+	 */
+	private String transferOutNo;
+
+	/**
+	 * 支付宝转账订单号
+	 */
+	private String transactionId;
+
+	/**
+	 * 转账账户
+	 */
+	private String account;
+
+	/**
+	 * 转账用户真实姓名
+	 */
+	private String name;
+
+	private BigDecimal money;
+
+	/**
+	 * 分销积分
+	 */
+	private BigDecimal points;
+
+	/**
+	 * 转账类型 默认支付宝AliPay
+	 */
+	private String type;
+
+	/**
+	 * 1:默认分销作用
+	 */
+	private Integer scope;
+
+	/**
+	 * 1成功,0失败
+	 */
+	private Integer status;
+
+	private String errorMsg;
+
+	/**
+	 * 转账日期
+	 */
+	private Date transferTime;
+}

+ 7 - 0
netflix-dao/src/main/java/com/cyksj/model/request/ApplyMoneyReq.java

@@ -4,6 +4,8 @@ import com.cyksj.model.entity.DistributeMoneyApply;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.math.BigDecimal;
+
 /*
  *项目名: netflix
  *文件名: ApplyMoneyReq
@@ -18,4 +20,9 @@ public class ApplyMoneyReq {
 	private DistributeMoneyApply.Type type;
 
 	private String realName;
+
+	/**
+	 * 提取的money
+	 */
+	private BigDecimal money;
 }

+ 48 - 0
netflix-dao/src/main/java/com/cyksj/model/request/TransferAccountsReq.java

@@ -0,0 +1,48 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: TransferAccountsReq
+ *创建者: JavaZou
+ *创建时间:2023/2/28 10:09
+ */
+@Getter
+@Setter
+public class TransferAccountsReq {
+	/**
+	 * 转账金额
+	 */
+	@NotNull
+	private BigDecimal money;
+
+	/**
+	 * 转账账户
+	 */
+	@NotNull
+	private String account;
+
+	/**
+	 * 转账账户真实姓名
+	 */
+	private String name;
+
+	/**
+	 * alipay、wechat
+	 */
+	private String type;
+
+	private BigDecimal points;
+
+	/**
+	 * 默认1分销作用
+	 */
+	private Integer scope;
+
+	private Long userId;
+}

+ 2 - 0
netflix-service/src/main/java/com/cyksj/config/zfb/ZfbProductCode.java

@@ -12,6 +12,8 @@ import lombok.Getter;
 public enum ZfbProductCode {
 	MOBILE_WEB("支付宝手机网页支付", "QUICK_WAP_PAY"),
 	PC_WEB("支付宝电脑网站支付", "FAST_INSTANT_TRADE_PAY"),
+	TRANS_ACCOUNT_NO_PWD("单笔无密转账到固定支付宝账户", "TRANS_ACCOUNT_NO_PWD"),
+	STD_RED_PACKET("支付宝红包转账", "STD_RED_PACKET"),
 	;
 	String desc;
 	String productCode;

+ 1 - 1
netflix-web/src/main/java/com/cyksj/web/controller/mail/MailService.java → netflix-service/src/main/java/com/cyksj/service/mail/MailService.java

@@ -1,4 +1,4 @@
-package com.cyksj.web.controller.mail;
+package com.cyksj.service.mail;
 
 /*
  *项目名: netflix

+ 2 - 2
netflix-web/src/main/java/com/cyksj/web/controller/mail/impl/MailServiceImpl.java → netflix-service/src/main/java/com/cyksj/service/mail/impl/MailServiceImpl.java

@@ -1,8 +1,8 @@
-package com.cyksj.web.controller.mail.impl;
+package com.cyksj.service.mail.impl;
 
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.redis.RedisService;
-import com.cyksj.web.controller.mail.MailService;
+import com.cyksj.service.mail.MailService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;

+ 13 - 1
netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java

@@ -4,9 +4,11 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.cyksj.dto.Result;
 import com.cyksj.model.dto.AliPayParams;
 import com.cyksj.model.dto.H5JsPayParams;
-import com.cyksj.model.entity.*;
+import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.entity.RealGoodsInterestUser;
 import com.cyksj.model.manage.views.OrderDonView;
 import com.cyksj.model.request.OrderPayRequest;
+import com.cyksj.model.request.TransferAccountsReq;
 import com.cyksj.model.request.WxOrderRefundReq;
 import com.cyksj.model.request.ZfbOrderRefundReq;
 
@@ -80,4 +82,14 @@ public interface OrderDonService extends IService<OrderDon> {
     void updateHasPaymentInterestRealGoodsPayTime();
 
     void saveTransport(Long addressId, Long orderId);
+
+    /**
+     * 支付宝红包转账
+     */
+    Boolean transferAccounts(TransferAccountsReq transferAccountsReq) throws Exception;
+
+    /**
+     * 查询支付宝转账状态
+     */
+    String getTransFerStatusByTid(String translationId) throws Exception;
 }

+ 101 - 11
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -4,16 +4,15 @@ import cn.hutool.core.date.DateField;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayClient;
 import com.alipay.api.AlipayRequest;
-import com.alipay.api.domain.AlipayTradePagePayModel;
-import com.alipay.api.domain.AlipayTradeRefundModel;
-import com.alipay.api.domain.AlipayTradeWapPayModel;
+import com.alipay.api.AlipayResponse;
+import com.alipay.api.domain.*;
 import com.alipay.api.internal.util.AlipaySignature;
-import com.alipay.api.request.AlipayTradePagePayRequest;
-import com.alipay.api.request.AlipayTradeRefundRequest;
-import com.alipay.api.request.AlipayTradeWapPayRequest;
+import com.alipay.api.request.*;
+import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
 import com.alipay.api.response.AlipayTradeRefundResponse;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -21,6 +20,7 @@ import com.cyksj.common.AliPayCommon;
 import com.cyksj.common.EnvCommonService;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.common.constant.TaskTypeEnum;
+import com.cyksj.common.constant.TransferConstant;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
@@ -43,12 +43,10 @@ import com.cyksj.mapper.market.task.TaskTypeMapper;
 import com.cyksj.model.dto.AliPayParams;
 import com.cyksj.model.dto.CouponPopularizeDto;
 import com.cyksj.model.dto.H5JsPayParams;
+import com.cyksj.model.entity.Address;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.OrderDonView;
-import com.cyksj.model.request.OrderAttach;
-import com.cyksj.model.request.OrderPayRequest;
-import com.cyksj.model.request.WxOrderRefundReq;
-import com.cyksj.model.request.ZfbOrderRefundReq;
+import com.cyksj.model.request.*;
 import com.cyksj.model.response.AliPayRefundRep;
 import com.cyksj.model.views.CouponNewUserView;
 import com.cyksj.model.views.CouponUserView;
@@ -170,6 +168,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final MarketFrontService marketFrontService;
 
+	private final TransferAccountsRecordMapper transferAccountsRecordMapper;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -1149,6 +1149,71 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		orderDonTransportMapper.insert(transport);
 	}
 
+	@Override
+	public Boolean transferAccounts(TransferAccountsReq transferAccountsReq) throws Exception {
+		Long userId = transferAccountsReq.getUserId();
+		String account = transferAccountsReq.getAccount();
+		String name = transferAccountsReq.getName();
+		BigDecimal money = transferAccountsReq.getMoney();
+		String type = transferAccountsReq.getType();
+		BigDecimal points = transferAccountsReq.getPoints();
+		/* 生成商户转账订单号 */
+		String donNo = SEQUENCE.nextId().toString();
+		if (StrUtil.isEmpty(type)) {
+			type = TransferConstant.ALIPAY;
+		}
+		Integer scope = transferAccountsReq.getScope();
+		ShopConfig shopConfig = shopConfigMapper.getByAppId(ShopConfig.ZFB_DEFAULT_APP_ID);
+
+		AlipayClient alipayClient = AliPayCommon.getAlipayClient(shopConfig);
+
+		AlipayRequest alipayRequest = aliPayTransferAccountsRequest(donNo, account, name, money);
+
+		AlipayResponse response = alipayClient.certificateExecute(alipayRequest);
+		if (response.isSuccess()) {
+			log.info("支付宝转账金额:{}至用户:{}成功", money.divide(BigDecimal.valueOf(100)), userId);
+			saveTransferRecord(userId, donNo, account, name, money, points, type, scope, response.getBody(), null);
+			return true;
+		}
+		log.info("支付宝转账金额:{}至用户:{}失败", money.divide(BigDecimal.valueOf(100)), userId);
+		saveTransferRecord(userId, donNo, account, name, money, points, type, scope, response.getBody(), response.getSubMsg());
+		return false;
+	}
+
+	@Override
+	public String getTransFerStatusByTid(String translationId) throws Exception {
+		ShopConfig shopConfig = shopConfigMapper.getByAppId(ShopConfig.ZFB_DEFAULT_APP_ID);
+		AlipayClient alipayClient = AliPayCommon.getAlipayClient(shopConfig);
+		AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest();
+		AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel();
+		model.setOrderId(translationId);
+		model.setBizScene(TransferConstant.DIRECT_TRANSFER);
+		model.setProductCode(ZfbProductCode.STD_RED_PACKET.getProductCode());
+		request.setBizModel(model);
+		AlipayFundTransCommonQueryResponse response = alipayClient.certificateExecute(request);
+		return response.getBody();
+	}
+
+	private AlipayRequest aliPayTransferAccountsRequest(String donNo, String account, String name, BigDecimal money) {
+		//支付宝转账
+		AlipayFundTransUniTransferRequest transUniTransferRequest = new AlipayFundTransUniTransferRequest();
+		//转账参数
+		AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
+		model.setOutBizNo(donNo);
+		model.setTransAmount(money.toString());
+		model.setProductCode(ZfbProductCode.STD_RED_PACKET.getProductCode());
+		model.setBizScene(TransferConstant.DIRECT_TRANSFER);
+		model.setOrderTitle("红包转账");
+		//红包业务必传,取值REDPACKET
+		model.setBusinessParams(TransferConstant.RED_PACKET);
+		Participant payeeInfo = new Participant();
+		payeeInfo.setIdentity(account);
+		payeeInfo.setIdentityType(TransferConstant.ALIPAY_LOGON_ID);
+		payeeInfo.setName(name);
+		transUniTransferRequest.setBizModel(model);
+		return transUniTransferRequest;
+	}
+
 	public AliPayParams commonAliPay(Long orderId, String productCode, String appId, String qrPayMode) throws Exception {
 		ShopConfig shopConfig = shopConfigMapper.getByAppId(Optional.ofNullable(appId).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
 
@@ -1322,7 +1387,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				if (points != null && points.compareTo(BigDecimal.ZERO) > 0) {
 					log.info("用户{}邀请{},产生分销订单分发积分记录入库", userDistributeShared.getUserId(), order.getUserId());
 					distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.waiting);
-					distributeWaitingSendPoints.setSendTime(DateUtil.offsetDay(order.getPayTime(), 7));
+					distributeWaitingSendPoints.setSendTime(DateUtil.offsetDay(order.getPayTime(), 3));
 					distributeWaitingSendPointsMapper.insert(distributeWaitingSendPoints);
 				}
 			}
@@ -1538,4 +1603,29 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			}
 		}
 	}
+
+	/**
+	 * 保存转账记录
+	 */
+	public void saveTransferRecord(Long userId, String donNo, String account, String name, BigDecimal money, BigDecimal points, String type, Integer scope, String body, String error) throws Exception {
+		TransferAccountsRecord record = new TransferAccountsRecord();
+		JSONObject re = Jsons.parseObject(body, JSONObject.class);
+		String transactionId = re.getStr("order_id");
+		String transDate = re.getStr("trans_date");
+		record.setUserId(userId);
+		record.setAccount(account);
+		record.setName(name);
+		record.setMoney(money);
+		record.setType(type);
+		record.setScope(scope);
+		Optional.ofNullable(error).ifPresent(msg -> {
+			record.setErrorMsg(msg);
+			record.setStatus(0);
+		});
+		record.setPoints(points);
+		record.setTransferOutNo(donNo);
+		record.setTransactionId(transactionId);
+		record.setTransferTime(DateTime.of(transDate, "yyyy-MM-dd HH:mm:ss"));
+		transferAccountsRecordMapper.insert(record);
+	}
 }

+ 0 - 1
netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java

@@ -323,5 +323,4 @@ public class CmsOrderController {
 		SearchResult<OrderCommentView> search = beanSearcher.search(OrderCommentView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
 	}
-
 }

+ 19 - 0
netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java

@@ -282,6 +282,25 @@ public class OrderController {
 		return "success";
 	}
 
+//    /**
+//     * 支付宝转账
+//     */
+//    @PostMapping("/zfb/transfer/accounts")
+//    @NoSubmit
+//    public Result<String> zfbTransferAccounts(@RequestBody TransferAccountsReq transferAccountsReq) throws Exception {
+//        orderDonService.transferAccounts(transferAccountsReq);
+//        return GatewayResponse.SUCCESS.newBuilder().toResult("转账成功");
+//    }
+
+    /**
+     * 查询支付宝转账状态
+     */
+    @GetMapping("/zfb/transfer/status")
+    public Result<String> getTransFerStatusByTid(String translationId) throws Exception {
+        String body = orderDonService.getTransFerStatusByTid(translationId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(body);
+    }
+
     /**
      * 获取订单列表
      */

+ 1 - 1
netflix-web/src/main/java/com/cyksj/web/controller/user/AuthorizationController.java

@@ -37,7 +37,7 @@ import com.cyksj.service.distribute.DistributeService;
 import com.cyksj.service.template.TemplateCommonService;
 import com.cyksj.service.user.UserService;
 import com.cyksj.service.wechat.WeChatService;
-import com.cyksj.web.controller.mail.MailService;
+import com.cyksj.service.mail.MailService;
 import com.cyksj.web.util.StpUserUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;

+ 26 - 2
netflix-web/src/main/java/com/cyksj/web/controller/user/DistributePopularizeController.java

@@ -20,10 +20,12 @@ import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper;
 import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.request.ApplyMoneyReq;
+import com.cyksj.model.request.TransferAccountsReq;
 import com.cyksj.model.views.DistributeMoneyApplyView;
 import com.cyksj.model.views.DistributePopularizeOrdersView;
 import com.cyksj.model.views.DistributePopularizeView;
 import com.cyksj.model.views.UserDistributeView;
+import com.cyksj.service.order.OrderDonService;
 import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
@@ -68,6 +70,8 @@ public class DistributePopularizeController {
 
 	private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper;
 
+	private final OrderDonService orderService;
+
 	/**
 	 * 推广订单明细
 	 */
@@ -147,12 +151,13 @@ public class DistributePopularizeController {
 	@NoSubmit
 	@PostMapping("/post/applyMoney")
 	@Transactional(rollbackFor = Throwable.class)
-	public Result<Integer> applyMoney(@RequestBody ApplyMoneyReq applyMoneyReq) {
+	public Result<Integer> applyMoney(@RequestBody ApplyMoneyReq applyMoneyReq) throws Exception {
 		Long userId = StpUserUtil.getLoginIdAsLong();
 		User user = userMapper.selectById(userId);
 		if (user == null) {
 			throw BusinessRuntimeException.getInstance("请先授权登录");
 		}
+		BigDecimal applyMoney = applyMoneyReq.getMoney();
 		if (ObjectUtil.hasEmpty(applyMoneyReq.getAccount(), applyMoneyReq.getRealName())) {
 			throw BusinessRuntimeException.getInstance("必填项不能为空");
 		}
@@ -170,14 +175,33 @@ public class DistributePopularizeController {
 		BigDecimal num = user.getPoints().divide(min, RoundingMode.DOWN);
 		BigDecimal points = min.multiply(num);
 		Integer update = userMapper.subPoints(user.getId(), points);
+		BigDecimal money = num.multiply(distributePointsExchangeMoney.getMoney());
+		if (applyMoney.compareTo(money) > 0) {
+			throw BusinessRuntimeException.getInstance("超过可提现金额");
+		}
+		if (applyMoney.compareTo(BigDecimal.valueOf(4 * 100 * 100)) > 0) {
+			throw BusinessRuntimeException.getInstance("每日可体现金额不超过400");
+		}
 		if (update == 1) {
+			TransferAccountsReq req = new TransferAccountsReq();
+			req.setMoney(money);
+			req.setAccount(applyMoneyReq.getAccount());
+			req.setName(applyMoneyReq.getRealName());
+			req.setPoints(points);
+			req.setUserId(userId);
+
 			DistributeMoneyApply distributeMoneyApply = new DistributeMoneyApply();
 			distributeMoneyApply.setUserId(userId);
 			distributeMoneyApply.setPoints(points);
 			distributeMoneyApply.setMoney(num.multiply(distributePointsExchangeMoney.getMoney()));
-			distributeMoneyApply.setVerifyStatus(DistributeMoneyApply.Status.verifying);
 			distributeMoneyApply.setAccount(applyMoneyReq.getAccount());
 			distributeMoneyApply.setRealName(applyMoneyReq.getRealName());
+			if (orderService.transferAccounts(req)) {
+				distributeMoneyApply.setVerifyStatus(DistributeMoneyApply.Status.success);
+			}else {
+				distributeMoneyApply.setVerifyStatus(DistributeMoneyApply.Status.fail);
+				distributeMoneyApply.setImg("红包转账失败");
+			}
 			distributeMoneyApplyMapper.insert(distributeMoneyApply);
 			return GatewayResponse.SUCCESS.newBuilder().toResult(distributeMoneyApply.getMoney().intValue());
 		}