Bladeren bron

Merge branch 'register_pay'

# Conflicts:
#	netflix-service/src/main/java/com/cyksj/redis/RedisService.java
#	netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java
zoujiajian 3 jaren geleden
bovenliggende
commit
fc35458af8
22 gewijzigde bestanden met toevoegingen van 926 en 73 verwijderingen
  1. 1 4
      netflix-dao/src/main/java/com/cyksj/mapper/AppleAutoRegisterDataMapper.java
  2. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/RegisterGoodsDonMapper.java
  3. 37 0
      netflix-dao/src/main/java/com/cyksj/model/dto/OrderPayBuilderDto.java
  4. 80 0
      netflix-dao/src/main/java/com/cyksj/model/entity/RegisterGoodsDon.java
  5. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/RegisterOrderDon.java
  6. 2 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/RegisterReq.java
  7. 7 0
      netflix-dao/src/main/java/com/cyksj/model/request/AlipayOrderDonReq.java
  8. 82 0
      netflix-dao/src/main/java/com/cyksj/model/views/RegisterGoodsDonView.java
  9. 15 0
      netflix-service/src/main/java/com/cyksj/config/zfb/BaseZfbConfig.java
  10. 1 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  11. 4 14
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  12. 22 0
      netflix-service/src/main/java/com/cyksj/service/pay/AliPayCommonService.java
  13. 229 0
      netflix-service/src/main/java/com/cyksj/service/pay/impl/AliPayCommonServiceImpl.java
  14. 9 1
      netflix-service/src/main/java/com/cyksj/service/register/RegisterOrderDonService.java
  15. 133 21
      netflix-service/src/main/java/com/cyksj/service/register/impl/RegisterOrderDonServiceImpl.java
  16. 1 1
      netflix-service/src/main/java/com/cyksj/task/Scheduler.java
  17. 87 30
      netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java
  18. 96 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/RegisterGoodsDonController.java
  19. 12 1
      netflix-web/src/main/java/com/cyksj/web/controller/manage/register/CmsRegisterController.java
  20. 1 0
      netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java
  21. 63 0
      netflix-web/src/main/java/com/cyksj/web/controller/register/RegisterController.java
  22. 7 1
      netflix-web/src/main/java/com/cyksj/web/controller/user/UserController.java

+ 1 - 4
netflix-dao/src/main/java/com/cyksj/mapper/AppleAutoRegisterDataMapper.java

@@ -26,9 +26,6 @@ public interface AppleAutoRegisterDataMapper extends BaseMapper<AppleAutoRegiste
 			" and rd.status = 'noPayment'")
 	Integer checkNoPayOrder(@Param("userId") long userId, @Param("countryOrArea") AppleAutoRegisterData.CountryOrArea countryOrArea);
 
-	@Select("select rd.id from apple_auto_register_data ad inner join register_order_don rd on rd.id = ad.order_id" +
-			" where ad.status = true" +
-			" and ad.user_id != 0" +
-			" and rd.status = 'noPayment' and rd.created_time <= #{newDate}")
+	@Select("select id from register_order_don where status = 'noPayment' and created_time <= #{newDate}")
 	List<Long> getAllNoPayOrders(Date newDate);
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.RegisterGoodsDon;
+
+/*
+ *项目名: netflix
+ *文件名: RegisterGoodsDonMapper
+ *创建者: JavaZou
+ *创建时间:2023/7/3 15:03
+ */
+public interface RegisterGoodsDonMapper extends BaseMapper<RegisterGoodsDon> {
+}

+ 37 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/OrderPayBuilderDto.java

@@ -0,0 +1,37 @@
+package com.cyksj.model.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: OrderPayBuilderDto
+ *创建者: JavaZou
+ *创建时间:2023/6/15 14:28
+ */
+@Getter
+@Setter
+public class OrderPayBuilderDto {
+	private Long orderId;
+
+	private String orderNo;
+
+	private BigDecimal money;
+
+	private String productCode;
+
+	private String subject;
+
+	private String payMode;
+
+	private String notifyUrl;
+
+	private String returnUrl;
+
+	private String shopId;
+
+	private Date orderCreatedTime;
+}

+ 80 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/RegisterGoodsDon.java

@@ -0,0 +1,80 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/*
+ *项目名: netflix
+ *文件名: RegisterGoodsDon
+ *创建者: JavaZou
+ *创建时间:2023/7/3 15:00
+ */
+@Getter
+@Setter
+public class RegisterGoodsDon extends BaseEntity{
+	/**
+	 * 商品录入人
+	 */
+	private String writer;
+
+	/**
+	 * 标签
+	 */
+	private String tags;
+
+	/**
+	 * 商品名称
+	 */
+	@NotBlank(message = "请填写标题")
+	private String title;
+
+	/**
+	 * 缩略图
+	 */
+	private String logo;
+
+	/**
+	 * 背景图
+	 */
+	private String img;
+
+
+	/**
+	 * true 上架 / false 下架
+	 */
+	private Boolean status;
+
+	/**
+	 * true 存在 / false 删除
+	 */
+	private Boolean deleted;
+
+	/**
+	 * 详情
+	 */
+	private String detail;
+
+	/**
+	 * 描述
+	 */
+	private String remark;
+
+	private String banner;
+
+	/**
+	 * 排序
+	 */
+	private Integer sortBy;
+
+	/**
+	 * 虚拟销量
+	 */
+	private Integer virtualSold;
+
+	/**
+	 * 付款说明
+	 */
+	private String payDesc;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/RegisterOrderDon.java

@@ -62,9 +62,15 @@ public class RegisterOrderDon{
     @DbField("rd.order_no")
     private String orderNo;
 
+    @DbField("rd.goods_id")
+    private Long goodsId;
+
     @DbField("money")
     private BigDecimal money;
 
+    @DbField("rd.refund_money")
+    private BigDecimal refundMoney;
+
     /**
      * 微信订单号
      */
@@ -104,6 +110,9 @@ public class RegisterOrderDon{
     @DbField("rd.is_free")
     private Boolean isFree;
 
+    @DbField("rd.type")
+    private Type type;
+
     @DbField("rd.error_msg")
     private String errorMsg;
 
@@ -141,6 +150,21 @@ public class RegisterOrderDon{
     @TableField(fill = FieldFill.INSERT_UPDATE)
     private Date updateTime;
 
+    public enum Type {
+        WeChat("微信支付"),
+        ALI_PAY("支付宝"),
+        ;
+        private String desc;
+
+        Type(String desc) {
+            this.desc = desc;
+        }
+
+        public String getDesc() {
+            return desc;
+        }
+    }
+
     public enum Status {
         /**
          * 订单状态

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/RegisterReq.java

@@ -15,6 +15,8 @@ public class RegisterReq {
      */
     private String platform;
 
+    private Long goodsId;
+
     private String creationPoint;
 
     private String displayname;

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

@@ -17,5 +17,12 @@ public class AlipayOrderDonReq {
 	@NotNull
 	private Long orderId;
 
+	/**
+	 *  1、手机网页支付 2、电脑网页支付
+	 */
+	private Integer type;
+
+	private String payMode;
+
 	private String returnUrl;
 }

+ 82 - 0
netflix-dao/src/main/java/com/cyksj/model/views/RegisterGoodsDonView.java

@@ -0,0 +1,82 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/*
+ *项目名: netflix
+ *文件名: RegisterGoodsDonView
+ *创建者: JavaZou
+ *创建时间:2023/7/3 15:12
+ */
+@Getter
+@Setter
+@SearchBean(tables = "register_goods_don rd",
+		where = "rd.deleted is true and rd.status is true")
+public class RegisterGoodsDonView {
+	private Long id;
+
+	/**
+	 * 标签
+	 */
+	private String tags;
+
+	/**
+	 * 商品名称
+	 */
+	@NotBlank(message = "请填写标题")
+	private String title;
+
+	/**
+	 * 缩略图
+	 */
+	private String logo;
+
+	/**
+	 * 背景图
+	 */
+	private String img;
+
+	/**
+	 * 详情
+	 */
+	private String detail;
+
+	/**
+	 * 描述
+	 */
+	private String remark;
+
+	private String banner;
+
+	/**
+	 * 排序
+	 */
+	@JsonIgnore
+	private Integer sortBy;
+
+	/**
+	 * 虚拟销量
+	 */
+	@JsonIgnore
+	private Integer virtualSold;
+
+	@DbIgnore
+	private Integer sold;
+
+	/**
+	 * 购买通知信息
+	 */
+	@DbIgnore
+	private String notifyMsg;
+
+	/**
+	 * 付款说明
+	 */
+	private String payDesc;
+}

+ 15 - 0
netflix-service/src/main/java/com/cyksj/config/zfb/BaseZfbConfig.java

@@ -36,8 +36,12 @@ public class BaseZfbConfig {
 
 	public static String loginReturnUrl = "yinhe/web/loginTicket";
 
+	public static String zfb_register_login_return_url = "yinhe/web/registerTicket";
+
 	public static String notifyUrl = "applets/order/prepay/zfb/notify";
 
+	public static String zfb_register_notify_url = "applets/register/prepay/zfb/notify";
+
 	/**
 	 * qr_pay_mode PC扫码支付的方式。 跳转模式
 	 */
@@ -47,4 +51,15 @@ public class BaseZfbConfig {
 	 * qr_pay_mode PC扫码支付的方式。订单码 默认4嵌入
 	 */
 	public static String qrPayMode_orderCode = "4";
+
+
+	/**
+	 * 支付宝手机支付
+	 */
+	public static String ONE_STR = "1";
+
+	/**
+	 * 支付网页支付
+	 */
+	public static String TWO_STR = "2";
 }

+ 1 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -609,6 +609,7 @@ public class RedisService {
         PC_WEB_CACHE("pc_web_cache", "首页平台缓存", 10 * 60),
         H5_WEB_CACHE("h5_web_cache", "h5首页平台缓存", 10 * 60),
         YH_HOME_PAGHE_CACHE("yh_home_paghe_cache:", "银河首页缓存", 10 * 60),
+        REGISTER_HOME_PAGE_CACHE("register_home_page_cache:", "注册首页缓存", 10 * 60),
         CPS_BACK_LOGIN_KEY("cps_back_login:", "cps商务后台登录key", 3 * 60),
         CPS_AUTH_SUCCESS_KEY("cps_auth_success_key:%s", "cps后台微信授权", 60 * 10),
         QUESTION_RESPONSE_KEY("question_response_key:%s", "问卷回答key", 60 * 60 * 24L),

+ 4 - 14
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -68,6 +68,7 @@ import com.cyksj.service.market.MarketFrontService;
 import com.cyksj.service.market.task.TaskService;
 import com.cyksj.service.order.OrderCommonService;
 import com.cyksj.service.order.OrderDonService;
+import com.cyksj.service.pay.AliPayCommonService;
 import com.cyksj.service.relation.GroupRelationClearService;
 import com.cyksj.service.relation.GroupRelationFrontService;
 import com.cyksj.service.sys.SysConfigService;
@@ -199,6 +200,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final GroupsFuncService groupsFuncService;
 
+	private final AliPayCommonService aliPayCommonService;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -718,20 +721,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	@Override
 	public AliPayParams aliPay(Long orderId, String returnUrl, String productCode, String qrPayMode) throws Exception {
-		OrderDon orderDon = getById(orderId);
-		//获取支付宝默认商户
-		String appId = sysConfigService.getDefaultShopConfigByType("zfb");
-
-		if (orderDon.getPopularizeId() != null) {
-			ShopConfig shopConfig = shopConfigMapper.getByChannelPopularizeId(orderDon.getPopularizeId(), "zfb");
-			if (shopConfig != null) {
-				appId = shopConfig.getAppId();
-			}
-		}
-		orderDon.setType(OrderDon.Type.ALI_PAY);
-		orderDon.setShopId(appId);
-		this.updateById(orderDon);
-		return commonAliPay(orderId, returnUrl, productCode, appId, qrPayMode);
+		return aliPayCommonService.unifiedPay(orderId, productCode, qrPayMode, returnUrl);
 	}
 
 	@Override

+ 22 - 0
netflix-service/src/main/java/com/cyksj/service/pay/AliPayCommonService.java

@@ -0,0 +1,22 @@
+package com.cyksj.service.pay;
+
+import com.cyksj.model.dto.AliPayParams;
+
+/*
+ *项目名: netflix
+ *文件名: AliPayCommonService
+ *创建者: JavaZou
+ *创建时间:2023/6/14 15:19
+ */
+public interface AliPayCommonService {
+	/**
+	 *
+	 * @param orderId
+	 * @param productCode 支付产品码
+	 * @param returnUrl
+	 * @return
+	 */
+	AliPayParams unifiedPayRegister(Long orderId, String productCode, String payMode, String returnUrl) throws Exception;
+
+	AliPayParams unifiedPay(Long orderId, String productCode, String payMode, String returnUrl) throws Exception;
+}

+ 229 - 0
netflix-service/src/main/java/com/cyksj/service/pay/impl/AliPayCommonServiceImpl.java

@@ -0,0 +1,229 @@
+package com.cyksj.service.pay.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+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.AlipayTradeWapPayModel;
+import com.alipay.api.request.AlipayTradePagePayRequest;
+import com.alipay.api.request.AlipayTradeWapPayRequest;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.cyksj.common.EnvCommonService;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Codec;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.config.zfb.AliPayClientFactory;
+import com.cyksj.config.zfb.BaseZfbConfig;
+import com.cyksj.config.zfb.ZfbProductCode;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.RegisterOrderDonMapper;
+import com.cyksj.mapper.channel.ShopConfigMapper;
+import com.cyksj.model.dto.AliPayParams;
+import com.cyksj.model.dto.OrderPayBuilderDto;
+import com.cyksj.model.entity.GoodsDon;
+import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.entity.RegisterOrderDon;
+import com.cyksj.model.entity.ShopConfig;
+import com.cyksj.model.request.OrderAttach;
+import com.cyksj.service.pay.AliPayCommonService;
+import com.cyksj.service.sys.SysConfigService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: AliPayCommonServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/6/14 15:19
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class AliPayCommonServiceImpl implements AliPayCommonService {
+	private final RegisterOrderDonMapper registerOrderDonMapper;
+
+	private final OrderDonMapper orderDonMapper;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final ShopConfigMapper shopConfigMapper;
+
+	private final EnvCommonService envCommonService;
+
+	private final SysConfigService sysConfigService;
+
+	@Override
+	public AliPayParams unifiedPayRegister(Long orderId, String productCode, String payMode, String returnUrl) throws Exception {
+		RegisterOrderDon orderDon = registerOrderDonMapper.selectById(orderId);
+		Assert.notNull(orderDon, "订单不存在");
+		if (StrUtil.isEmpty(productCode)) throw BusinessRuntimeException.getInstance("支付异常");
+		//获取支付宝默认商户
+		String shopId = sysConfigService.getDefaultShopConfigByType("zfb");
+		orderDon.setShopId(shopId);
+		orderDon.setType(RegisterOrderDon.Type.ALI_PAY);
+		if (orderDon.getType() != RegisterOrderDon.Type.ALI_PAY) {
+			orderDon.setType(RegisterOrderDon.Type.ALI_PAY);
+		}
+		registerOrderDonMapper.updateById(orderDon);
+		//回调地址
+		String host = envCommonService.getHost();
+		String notifyUrl = String.format("%s%s", host, BaseZfbConfig.zfb_register_notify_url);
+		if (ZfbProductCode.MOBILE_WEB.getProductCode().equals(productCode) && BaseZfbConfig.qrPayMode_redirect.equals(payMode)) {
+			returnUrl = String.format("%s%s", envCommonService.getDomain(), BaseZfbConfig.zfb_register_login_return_url);
+		}
+		String subject = "注册服务";
+		AliPayParams aliPayParams = builderPayParams(orderDon.getId(),
+				orderDon.getOrderNo(),
+				orderDon.getShopId(),
+				orderDon.getMoney(),
+				orderDon.getCreatedTime(),
+				subject,
+				productCode,
+				payMode,
+				notifyUrl,
+				returnUrl);
+		return aliPayParams;
+	}
+
+	@Override
+	public AliPayParams unifiedPay(Long orderId, String productCode, String payMode, String returnUrl) throws Exception {
+		OrderDon orderDon = orderDonMapper.selectById(orderId);
+		//获取支付宝默认商户
+		String appId = sysConfigService.getDefaultShopConfigByType("zfb");
+		if (orderDon.getPopularizeId() != null) {
+			ShopConfig shopConfig = shopConfigMapper.getByChannelPopularizeId(orderDon.getPopularizeId(), "zfb");
+			if (shopConfig != null) {
+				appId = shopConfig.getAppId();
+			}
+		}
+		if (OrderDon.Type.ALI_PAY != orderDon.getType()) {
+			orderDon.setType(OrderDon.Type.ALI_PAY);
+		}
+		orderDon.setShopId(appId);
+		orderDonMapper.updateById(orderDon);
+		GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
+		String subject = goodsDon.getTitle().contains("ChatGPT") ? "AI订阅" : goodsDon.getTitle();
+		//回调地址
+		String host = envCommonService.getHost();
+		String notifyUrl = String.format("%s%s", host, BaseZfbConfig.notifyUrl);
+		if (ZfbProductCode.MOBILE_WEB.getProductCode().equals(productCode) && BaseZfbConfig.qrPayMode_redirect.equals(payMode)) {
+			returnUrl = String.format("%s%s", envCommonService.getDomain(), BaseZfbConfig.loginReturnUrl);
+		}
+		AliPayParams aliPayParams = builderPayParams(orderDon.getId(),
+				orderDon.getOrderNo(),
+				orderDon.getShopId(),
+				orderDon.getMoney(),
+				orderDon.getCreatedTime(),
+				subject,
+				productCode,
+				payMode,
+				notifyUrl,
+				returnUrl);
+		return aliPayParams;
+	}
+
+	public AliPayParams builderPayParams(Long orderId, String orderNo, String shopId, BigDecimal money, Date orderCreatedTime, String subject, String productCode, String payMode, String notifyUrl, String returnUrl) throws Exception {
+		OrderPayBuilderDto orderPayBuilderDto = new OrderPayBuilderDto();
+		orderPayBuilderDto.setOrderId(orderId);
+		orderPayBuilderDto.setMoney(money);
+		orderPayBuilderDto.setOrderNo(orderNo);
+		orderPayBuilderDto.setSubject(subject);
+		orderPayBuilderDto.setOrderCreatedTime(orderCreatedTime);
+		orderPayBuilderDto.setProductCode(productCode);
+		orderPayBuilderDto.setPayMode(payMode);
+		orderPayBuilderDto.setReturnUrl(returnUrl);
+		orderPayBuilderDto.setNotifyUrl(notifyUrl);
+		orderPayBuilderDto.setShopId(shopId);
+		AliPayParams aliPayParams = commonAliPay(orderPayBuilderDto);
+		return aliPayParams;
+	}
+
+	public AliPayParams commonAliPay(OrderPayBuilderDto orderPayBuilderDto) throws Exception {
+		AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(orderPayBuilderDto.getShopId()).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
+		String returnUrl = orderPayBuilderDto.getReturnUrl();
+		String notifyUrl = orderPayBuilderDto.getNotifyUrl();
+		// 创建API对应的request
+		AlipayRequest alipayRequest = getAliAayRequest(orderPayBuilderDto);
+		if (alipayRequest == null) {
+			throw BusinessRuntimeException.getInstance("支付宝不支持该支付方式:{0}", orderPayBuilderDto.getProductCode());
+		}
+		if (StrUtil.isNotBlank(returnUrl)) {
+			alipayRequest.setReturnUrl(returnUrl);
+		}
+		alipayRequest.setNotifyUrl(notifyUrl);
+		String form = null;
+		try {
+			//调用SDK生成表单
+			//pagePay 统一下单接口
+			form = alipayClient.pageExecute(alipayRequest).getBody();
+		} catch (AlipayApiException e) {
+			log.error("支付宝生成表单错误:{}", StringUtil.getErrorText(e));
+		}
+		log.info("支付宝返回参数:{}", form);
+		return new AliPayParams(form);
+	}
+
+	/**
+	 * 支付宝获取不同的request
+	 */
+	private AlipayRequest getAliAayRequest(OrderPayBuilderDto payBuilderDto) throws Exception {
+		Long orderId = payBuilderDto.getOrderId();
+		BigDecimal money = payBuilderDto.getMoney();
+		String orderNo = payBuilderDto.getOrderNo();
+		//productCode 销售产品码,与支付宝签约的产品码名称
+		String productCode = payBuilderDto.getProductCode();
+		String subject = payBuilderDto.getSubject();
+		Date orderCreatedTime = payBuilderDto.getOrderCreatedTime();
+		//网页支付跳转模式
+		String qrPayMode = payBuilderDto.getPayMode();
+		OrderAttach attach = new OrderAttach();
+		attach.setO(orderId);
+		String body = Codec.DoBase64.custom()
+				.setData(Jsons.toJson(attach)).encodeAsText();
+		String moneyStr = money.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN).toString();
+		if (ZfbProductCode.MOBILE_WEB.getProductCode().equals(productCode)) {
+			//手机网站支付
+			AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
+			//手机网站支付支付参数
+			AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
+			alipayTradeWapPayModel.setBody(body);
+			alipayTradeWapPayModel.setOutTradeNo(orderNo);
+			alipayTradeWapPayModel.setTotalAmount(moneyStr);
+			alipayTradeWapPayModel.setSubject(subject);
+			alipayTradeWapPayModel.setProductCode(productCode);
+			//5分钟订单失效时间
+			alipayTradeWapPayModel.setTimeExpire(DateUtil.offsetMinute(orderCreatedTime, 5).toString());
+			alipayTradeWapPayRequest.setBizModel(alipayTradeWapPayModel);
+			return alipayTradeWapPayRequest;
+		} else if (ZfbProductCode.PC_WEB.getProductCode().equals(productCode)) {
+			//电脑网站支付
+			AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
+			//电脑网站支付参数
+			AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
+			alipayTradePagePayModel.setBody(body);
+			alipayTradePagePayModel.setOutTradeNo(orderNo);
+			alipayTradePagePayModel.setTotalAmount(moneyStr);
+			alipayTradePagePayModel.setSubject(subject);
+			alipayTradePagePayModel.setProductCode(productCode);
+			//5分钟订单失效时间
+			alipayTradePagePayModel.setTimeExpire(DateUtil.offsetMinute(orderCreatedTime, 5).toString());
+			if (StrUtil.isEmpty(qrPayMode)) {
+				qrPayMode = BaseZfbConfig.qrPayMode_orderCode;
+			}
+			alipayTradePagePayModel.setQrPayMode(qrPayMode);
+			alipayTradePagePayRequest.setBizModel(alipayTradePagePayModel);
+			return alipayTradePagePayRequest;
+		}
+		return null;
+	}
+}

+ 9 - 1
netflix-service/src/main/java/com/cyksj/service/register/RegisterOrderDonService.java

@@ -2,10 +2,12 @@ package com.cyksj.service.register;
 
 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.RegisterOrderDon;
 import com.cyksj.model.entity.SpotifyUnLimitRecord;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.AlipayOrderDonReq;
 import com.cyksj.model.request.OrderRefundReq;
 import com.cyksj.model.views.CouponUserView;
 
@@ -25,7 +27,7 @@ public interface RegisterOrderDonService extends IService<RegisterOrderDon> {
 
     void prepayNotify(Map<String, String> map) throws Exception;
 
-    Result<String> wxRefund(OrderRefundReq refundReq) throws Exception;
+    Result<String> wxRefund(OrderRefundReq refundReq, RegisterOrderDon registerOrderDon) throws Exception;
 
     void wxRefundNotify(Map<String, String> map) throws Exception;
 
@@ -34,4 +36,10 @@ public interface RegisterOrderDonService extends IService<RegisterOrderDon> {
     CouponUserView spotifyUnLimit(SpotifyUnLimitRecord spotifyUnLimitRecord);
 
     CouponUserView getAvailableSpotifyCoupon(long userId);
+
+	void unifiedRefund(OrderRefundReq refundReq) throws Exception;
+
+    AliPayParams zfbUnifiedPay(AlipayOrderDonReq re) throws Exception;
+
+    void aliPayNotify(Map<String, String> params) throws Exception;
 }

+ 133 - 21
netflix-service/src/main/java/com/cyksj/service/register/impl/RegisterOrderDonServiceImpl.java

@@ -4,6 +4,11 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.domain.AlipayTradeRefundModel;
+import com.alipay.api.internal.util.AlipaySignature;
+import com.alipay.api.request.AlipayTradeRefundRequest;
+import com.alipay.api.response.AlipayTradeRefundResponse;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.cyksj.common.exception.BusinessRuntimeException;
@@ -12,6 +17,9 @@ import com.cyksj.common.util.Codec;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.common.util.Xmls;
 import com.cyksj.config.WeChatConfig;
+import com.cyksj.config.zfb.AliPayClientFactory;
+import com.cyksj.config.zfb.BaseZfbConfig;
+import com.cyksj.config.zfb.ZfbProductCode;
 import com.cyksj.dto.RedisKey;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
@@ -21,14 +29,17 @@ import com.cyksj.mapper.SpotifyUnLimitRecordMapper;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.mapper.channel.ShopConfigMapper;
 import com.cyksj.mapper.manage.coupon.CouponMapper;
+import com.cyksj.model.dto.AliPayParams;
 import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.AlipayOrderDonReq;
 import com.cyksj.model.request.OrderAttach;
 import com.cyksj.model.request.OrderRefundReq;
 import com.cyksj.model.views.CouponUserView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.mange.coupon.CouponCommonService;
+import com.cyksj.service.pay.AliPayCommonService;
 import com.cyksj.service.register.RegisterOrderDonService;
 import com.cyksj.service.register.SpotifyService;
 import com.cyksj.service.sys.SysConfigService;
@@ -45,6 +56,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
@@ -89,6 +102,8 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
 
     private final ShopConfigMapper shopConfigMapper;
 
+    private final AliPayCommonService aliPayCommonService;
+
     private static final Long EXPIRY_TIME = 1000 * 60 * 5L;
 
     /**
@@ -133,6 +148,8 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
         orderDon.setIsFree(isFree);
         orderDon.setMoney(isFree ? BigDecimal.ZERO : BigDecimal.valueOf(("apple".equals(req.getPlatform()) && "auto".equals(req.getAppleRegisterType())) ? map.get("appleAuto") : map.get(req.getPlatform())));
         orderDon.setStatus(isFree ? RegisterOrderDon.Status.hasPayment : RegisterOrderDon.Status.noPayment);
+        String shopId = sysConfigService.getDefaultShopConfigByType("zfb");
+        orderDon.setShopId(shopId);
         save(orderDon);
         //apple
         handleAppleIdAuto(userId, req, orderDon);
@@ -181,11 +198,11 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
                 appleAutoRegisterData.setUserId(0l);
                 appleAutoRegisterData.setOrderId(0l);
                 appleAutoRegisterDataMapper.updateById(appleAutoRegisterData);
-                //订单关闭
-                registerOrderDon.setStatus(RegisterOrderDon.Status.close);
-                registerOrderDonMapper.updateById(registerOrderDon);
                 log.info("未支付appleID自动注册订单:{},修改appleID使用状态", orderId);
             }
+            //订单关闭
+            registerOrderDon.setStatus(RegisterOrderDon.Status.close);
+            registerOrderDonMapper.updateById(registerOrderDon);
         }
     }
 
@@ -245,6 +262,79 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
         return couponUserView;
     }
 
+    @Override
+    public void unifiedRefund(OrderRefundReq refundReq) throws Exception {
+        Long orderId = refundReq.getOrderId();
+        RegisterOrderDon registerOrderDon = this.getById(orderId);
+        if (registerOrderDon == null) throw BusinessRuntimeException.getInstance("订单不存在");
+        if (registerOrderDon.getStatus() == RegisterOrderDon.Status.refund) throw BusinessRuntimeException.getInstance("该订单已退款");
+
+        if (registerOrderDon.getStatus() != RegisterOrderDon.Status.error && registerOrderDon.getStatus() != RegisterOrderDon.Status.hasPayment) {
+            throw BusinessRuntimeException.getInstance("该订单状态不允许退款");
+        }
+        if (registerOrderDon.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
+            throw BusinessRuntimeException.getInstance("该订单金额为0,无需退款");
+        }
+        if (!redisService.setNx(String.format("%s", refundReq.getOrderId()), refundReq.getOrderId(), 10l)) {
+            throw BusinessRuntimeException.getInstance("请勿重复点击,正在退款中..");
+        }
+        RegisterOrderDon.Type type = registerOrderDon.getType();
+        if (type == RegisterOrderDon.Type.WeChat) {
+            wxRefund(refundReq, registerOrderDon);
+        }
+        if (type == RegisterOrderDon.Type.ALI_PAY) {
+            zfbRefund(refundReq, registerOrderDon);
+        }
+    }
+
+    @Override
+    public AliPayParams zfbUnifiedPay(AlipayOrderDonReq re) throws Exception {
+        String productCode = StrUtil.EMPTY;
+        if (re.getType() == 1) {
+            productCode = ZfbProductCode.MOBILE_WEB.getProductCode();
+        }
+        if (re.getType() == 2) {
+            productCode = ZfbProductCode.PC_WEB.getProductCode();
+        }
+        return aliPayCommonService.unifiedPayRegister(re.getOrderId(), productCode, re.getPayMode(), re.getReturnUrl());
+    }
+
+    @Override
+    public void aliPayNotify(Map<String, String> params) throws Exception {
+        //调用SDK验证签名
+        String body = Codec.DoBase64.custom().setData(params.get("body")).decodeAsText();
+        OrderAttach orderAttach = Jsons.parseObject(body, OrderAttach.class);
+        Long oderId = orderAttach.getO();
+        RegisterOrderDon orderDon = getById(oderId);
+        if (null == orderDon) {
+            throw BusinessRuntimeException.getInstance("订单不存在.");
+        }
+        String appId = params.get("app_id");
+        boolean signVerified = AlipaySignature.rsaCheckV1(params, shopConfigMapper.getByAppId(appId).getPublicKey(), BaseZfbConfig.charset, BaseZfbConfig.signType);
+        if (!signVerified) {
+            log.error("支付宝回调校验签名错误,自定义入参:{}", params.get("body"));
+            throw BusinessRuntimeException.getInstance("支付宝回调校验签名错误");
+        }
+        String transactionId = params.get("trade_no");
+        String payTimeStr = params.get("gmt_payment");
+        if (!orderDon.getStatus().equals(RegisterOrderDon.Status.noPayment) && !orderDon.getStatus().equals(RegisterOrderDon.Status.close)) {
+            log.info("支付宝已回调,重复修改状态 id:{}", orderDon.getId());
+            return;
+        }
+
+        // 更改订单状态
+        orderDon.setTransactionId(transactionId);
+        orderDon.setStatus(RegisterOrderDon.Status.hasPayment);
+        AppleAutoRegisterData appleAutoRegisterData = appleAutoRegisterDataMapper.selectOne(Wrappers.lambdaQuery(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getOrderId, orderDon.getId()).eq(AppleAutoRegisterData::getStatus, true));
+        if (appleAutoRegisterData != null) {
+            orderDon.setStatus(RegisterOrderDon.Status.complete);
+        }
+        if (StrUtil.isNotBlank(payTimeStr)) {
+            orderDon.setPayTime(DateUtil.parse(payTimeStr, "yyyy-MM-dd HH:mm:ss"));
+        }
+        this.updateById(orderDon);
+    }
+
     @Override
     public H5JsPayParams pay(Long orderId) throws Exception {
         log.info("注册 账号调起微信支付[start] orderId:{}", orderId);
@@ -332,30 +422,16 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
     }
 
     @Override
-    public Result<String> wxRefund(OrderRefundReq refundReq) throws Exception {
-        RegisterOrderDon registerOrderDon = this.getById(refundReq.getOrderId());
-        if (registerOrderDon == null) {
-            throw BusinessRuntimeException.getInstance("该订单不存在");
-        }
-        if (registerOrderDon.getStatus() == RegisterOrderDon.Status.refund) {
-            throw BusinessRuntimeException.getInstance("该订单已退款");
-        }
-        if (registerOrderDon.getStatus() != RegisterOrderDon.Status.error && registerOrderDon.getStatus() != RegisterOrderDon.Status.hasPayment) {
-            throw BusinessRuntimeException.getInstance("该订单状态不允许退款");
-        }
-        if (registerOrderDon.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
-            throw BusinessRuntimeException.getInstance("该订单金额为0,无需退款");
-        }
-        if (!redisService.setNx(String.format("%s", refundReq.getOrderId()), refundReq.getOrderId(), 10l)) {
-            throw BusinessRuntimeException.getInstance("请勿重复点击,正在退款中..");
-        }
+    public Result<String> wxRefund(OrderRefundReq refundReq,RegisterOrderDon registerOrderDon) throws Exception {
         long time = System.currentTimeMillis();
         //退款订单号
         String outRefundNo = Codec.DoDigest.custom()
                 .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
                 .setStringData(time + String.valueOf(registerOrderDon.getId()))
                 .toHexString();
-        refundReq.setRefundMoney(registerOrderDon.getMoney());
+        if (refundReq.getRefundMoney() == null) {
+            refundReq.setRefundMoney(registerOrderDon.getMoney());
+        }
         weChatService.refundWxOrder(weChatConfig.getAppid(),
                 Optional.ofNullable(registerOrderDon.getShopId()).orElse(ShopConfig.WX_DEFAULT_APP_ID),
                 registerOrderDon.getTransactionId(),
@@ -365,6 +441,7 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
                 weChatConfig.getDomain() + "manage/register/wx/refund/notify");
         //修改订单状态
         registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
+        registerOrderDon.setRefundMoney(refundReq.getRefundMoney());
         this.updateById(registerOrderDon);
         return GatewayResponse.SUCCESS.newBuilder().toResult("退款成功");
     }
@@ -395,4 +472,39 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
         }
         log.info("微信退款: 退款单号[{}] 退款成功.", outRefundNo);
     }
+
+    public void zfbRefund(OrderRefundReq refundReq, RegisterOrderDon registerOrderDon) throws Exception {
+        AlipayTradeRefundResponse response;
+        //支付宝退款
+        AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(registerOrderDon.getShopId()).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
+        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
+        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
+        //支付宝交易号
+        model.setTradeNo(registerOrderDon.getTransactionId());
+        if (refundReq.getRefundMoney() == null) {
+            refundReq.setRefundMoney(registerOrderDon.getMoney());
+        }
+        model.setRefundAmount(refundReq.getRefundMoney().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_EVEN).toString());
+        model.setQueryOptions(List.of("gmt_refund_pay"));
+        long time = System.currentTimeMillis();
+        //退款订单号
+        String outRefundNo = Codec.DoDigest.custom()
+                .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
+                .setStringData(time + String.valueOf(registerOrderDon.getId()))
+                .toHexString();
+        //退款请求号
+        model.setOutRequestNo(outRefundNo);
+        request.setBizModel(model);
+        String shopId = registerOrderDon.getShopId();
+        ShopConfig shopConfig = shopConfigMapper.selectOne(Wrappers.lambdaQuery(ShopConfig.class).eq(ShopConfig::getAppId, registerOrderDon.getShopId()));
+        if (shopId != null && shopConfig != null && shopConfig.getIsCert()) {
+            response = alipayClient.certificateExecute(request);
+        } else {
+            response = alipayClient.execute(request);
+        }
+        if (!response.isSuccess()) throw BusinessRuntimeException.getInstance("退款失败,e:{0}", response.getSubMsg());
+        registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
+        registerOrderDon.setRefundMoney(refundReq.getRefundMoney());
+        registerOrderDonMapper.updateById(registerOrderDon);
+    }
 }

+ 1 - 1
netflix-service/src/main/java/com/cyksj/task/Scheduler.java

@@ -300,7 +300,7 @@ public class Scheduler {
         //获取为支付订单
         DateTime now = new DateTime();
         Date newDate = DateUtil.offset(now, DateField.MINUTE, -5);
-        List<Long> orderDons = appleAutoRegisterDataMapper.getAllNoPayOrders(newDate);
+	    List<Long> orderDons = appleAutoRegisterDataMapper.getAllNoPayOrders(newDate);
         log.info("定时更新未支付AppleID自动注册订单 订单数:{}",orderDons.size());
         orderDons.forEach((orderId)->{
             registerOrderDonService.updateAppleAutoStatus(orderId);

+ 87 - 30
netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java

@@ -16,6 +16,7 @@ import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.GoodsDonSkuMapper;
 import com.cyksj.mapper.OrderDonMapper;
 import com.cyksj.mapper.SysConfigMapper;
+import com.cyksj.mapper.RegisterOrderDonMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.views.*;
 import com.cyksj.redis.RedisService;
@@ -44,11 +45,13 @@ import java.util.Optional;
 public class GoodsDonController {
 
     private final HttpServletRequest request;
-    
+
     private final BeanSearcher beanSearcher;
 
     private final OrderDonMapper orderDonMapper;
 
+    private final RegisterOrderDonMapper registerOrderDonMapper;
+
     private final GoodsDonSkuMapper goodsDonSkuMapper;
 
     private final RedisService redisService;
@@ -199,35 +202,7 @@ public class GoodsDonController {
                     .notIn(OrderDon::getStatus, Constant.noOrderStatus).select(OrderDon::getCreatedTime, OrderDon::getPayTime, OrderDon::getId)
                     .orderByDesc(OrderDon::getId)
                     .last("limit 1"));
-            StringBuilder notifyMsg = new StringBuilder();
-            if (orderDon == null) {
-                notifyMsg.append("点击购买立即上车");
-                data.setNotifyMsg(notifyMsg.toString());
-                return;
-            } else {
-                Date payTime = orderDon.getPayTime();
-                Date startTime = payTime != null ? payTime : orderDon.getCreatedTime();
-                long hour = DateUtil.between(startTime, now, DateUnit.HOUR);
-                if (hour == 0) {
-                    long minute = DateUtil.between(startTime, now, DateUnit.MINUTE);
-                    if (minute == 0) {
-                        notifyMsg.append("1分钟");
-                    } else {
-                        notifyMsg.append(minute);
-                        notifyMsg.append("分钟");
-                    }
-                } else {
-                    if (hour > 3) {
-                        int hours = RandomUtil.randomInt(3) + 1;
-                        notifyMsg.append(hours);
-                    } else {
-                        notifyMsg.append(hour);
-                    }
-                    notifyMsg.append("小时");
-                }
-            }
-            notifyMsg.append("前有人购买");
-            data.setNotifyMsg(notifyMsg.toString());
+	        data.setNotifyMsg(getPayMsgTime(data.getId(), now, 1));
         });
         redisService.setNx(pcCacheKey, list, RedisService.key.YH_HOME_PAGHE_CACHE.getTimeout());
         return GatewayResponse.SUCCESS.newBuilder().toResult(list);
@@ -272,6 +247,35 @@ public class GoodsDonController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(dataList);
     }
 
+    /**
+     * 注册首页平台展示
+     */
+    @GetMapping("/get/register")
+    public Result<List<RegisterGoodsDonView>> getRegisterGoodsDon() {
+        String registerCacheKey = RedisService.key.REGISTER_HOME_PAGE_CACHE.getName();
+        Object value = redisService.get(registerCacheKey);
+        if (value != null) {
+            try {
+                List<RegisterGoodsDonView> list = Jsons.parseList(value, RegisterGoodsDonView.class);
+                if (CollUtil.isNotEmpty(list)) {
+                    return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+                }
+            } catch (Exception e) {
+            }
+        }
+        MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+        List<RegisterGoodsDonView> dataList = beanSearcher.searchAll(RegisterGoodsDonView.class, builder.build());
+	    DateTime now = DateTime.now();
+	    dataList.forEach(data->{
+            Integer sold = registerOrderDonMapper.selectCount(Wrappers.lambdaQuery(RegisterOrderDon.class)
+                    .eq(RegisterOrderDon::getGoodsId, data.getId()).notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus));
+            data.setSold(sold + data.getVirtualSold());
+		    data.setNotifyMsg(getPayMsgTime(data.getId(), now, 2));
+        });
+        redisService.setNx(registerCacheKey, dataList, RedisService.key.REGISTER_HOME_PAGE_CACHE.getTimeout());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(dataList);
+    }
+
 
     /**
      * 获取商品详情
@@ -333,4 +337,57 @@ public class GoodsDonController {
         }
         return filter_goodsIds;
     }
+
+    /**
+     *
+     * @param goodsId
+     * @param type 1、普通,2、注册平台
+     * @return
+     */
+    public String getPayMsgTime(Long goodsId, DateTime now, Integer type) {
+	    Date startTime = null;
+	    StringBuilder notifyMsg = new StringBuilder();
+	    if (type == 1) {
+		    OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
+				    .eq(OrderDon::getGoodsId, goodsId)
+				    .notIn(OrderDon::getStatus, Constant.noOrderStatus).select(OrderDon::getCreatedTime, OrderDon::getPayTime, OrderDon::getId)
+				    .orderByDesc(OrderDon::getId)
+				    .last("limit 1"));
+		    if (orderDon == null) {
+			    notifyMsg.append("点击购买立即上车");
+			    return notifyMsg.toString();
+		    }
+		    startTime = orderDon.getPayTime() != null ? orderDon.getPayTime() : orderDon.getCreatedTime();
+	    } else if (type == 2) {
+		    RegisterOrderDon orderDon = registerOrderDonMapper.selectOne(Wrappers.lambdaQuery(RegisterOrderDon.class)
+				    .eq(RegisterOrderDon::getGoodsId, goodsId)
+				    .notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus).select(RegisterOrderDon::getCreatedTime, RegisterOrderDon::getPayTime, RegisterOrderDon::getId)
+				    .orderByDesc(RegisterOrderDon::getId)
+				    .last("limit 1"));
+		    if (orderDon == null) {
+			    return null;
+		    }
+		    startTime = orderDon.getPayTime() != null ? orderDon.getPayTime() : orderDon.getCreatedTime();
+	    }
+	    long hour = DateUtil.between(startTime, now, DateUnit.HOUR);
+	    if (hour == 0) {
+		    long minute = DateUtil.between(startTime, now, DateUnit.MINUTE);
+		    if (minute == 0) {
+			    notifyMsg.append("1分钟");
+		    } else {
+			    notifyMsg.append(minute);
+			    notifyMsg.append("分钟");
+		    }
+	    } else {
+		    if (hour > 3) {
+			    int hours = RandomUtil.randomInt(3) + 1;
+			    notifyMsg.append(hours);
+		    } else {
+			    notifyMsg.append(hour);
+		    }
+		    notifyMsg.append("小时");
+	    }
+	    notifyMsg.append("前有人购买");
+	    return notifyMsg.toString();
+    }
 }

+ 96 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/RegisterGoodsDonController.java

@@ -0,0 +1,96 @@
+package com.cyksj.web.controller.manage.goods;
+
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.RegisterGoodsDonMapper;
+import com.cyksj.model.entity.RegisterGoodsDon;
+import com.cyksj.redis.RedisService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Set;
+
+/*
+ *项目名: netflix
+ *文件名: RegisterGoodsDonController
+ *创建者: JavaZou
+ *创建时间:2023/7/3 15:03
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/manage/register/goods")
+public class RegisterGoodsDonController {
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	private final RegisterGoodsDonMapper registerGoodsDonMapper;
+
+	private final RedisService redisService;
+
+	@GetMapping("/get")
+	public Result<SearchResult<RegisterGoodsDon>> get(){
+		SearchResult<RegisterGoodsDon> search = beanSearcher.search(RegisterGoodsDon.class, MapUtils.flatBuilder(request.getParameterMap())
+				.field(RegisterGoodsDon::getDeleted,true)
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 新增 商品spu
+	 */
+	@PostMapping(value = "/post")
+	public Result<Long> spuInsert(@Validated @RequestBody RegisterGoodsDon registerGoodsDon) throws Exception {
+		// 新增商品
+		registerGoodsDonMapper.insert(registerGoodsDon);
+		Set<String> keys = redisService.keys(RedisService.key.REGISTER_HOME_PAGE_CACHE.getName() + "*");
+		redisService.del(keys.toArray(String[]::new));
+		return GatewayResponse.SUCCESS.newBuilder().toResult(registerGoodsDon.getId());
+	}
+
+	/**
+	 * 修改 商品spu
+	 */
+	@PutMapping(value = "/update")
+	public Result<String> spuUpdate(@Validated @RequestBody RegisterGoodsDon registerGoodsDon) throws Exception{
+		registerGoodsDonMapper.updateById(registerGoodsDon);
+		Set<String> keys = redisService.keys(RedisService.key.REGISTER_HOME_PAGE_CACHE.getName() + "*");
+		redisService.del(keys.toArray(String[]::new));
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+
+	@PutMapping("/put/status/{id}")
+	public Result<Boolean> updateStatus(@PathVariable Long id) {
+		RegisterGoodsDon registerGoodsDon = registerGoodsDonMapper.selectById(id);
+		if (registerGoodsDon == null) {
+			throw BusinessRuntimeException.getInstance("平台不存在");
+		}
+		registerGoodsDon.setStatus(!registerGoodsDon.getStatus());
+		registerGoodsDonMapper.updateById(registerGoodsDon);
+		Set<String> keys = redisService.keys(RedisService.key.REGISTER_HOME_PAGE_CACHE.getName() + "*");
+		redisService.del(keys.toArray(String[]::new));
+		return GatewayResponse.SUCCESS.newBuilder().toResult(registerGoodsDon.getStatus());
+	}
+
+	@DeleteMapping("/delete/{id}")
+	public Result<Long> deleteById(@PathVariable Long id) {
+		RegisterGoodsDon registerGoodsDon = registerGoodsDonMapper.selectById(id);
+		if (registerGoodsDon == null) {
+			throw BusinessRuntimeException.getInstance("平台不存在");
+		}
+		registerGoodsDon.setDeleted(false);
+		registerGoodsDonMapper.updateById(registerGoodsDon);
+		Set<String> keys = redisService.keys(RedisService.key.REGISTER_HOME_PAGE_CACHE.getName() + "*");
+		redisService.del(keys.toArray(String[]::new));
+		return GatewayResponse.SUCCESS.newBuilder().toResult(id);
+	}
+}

+ 12 - 1
netflix-web/src/main/java/com/cyksj/web/controller/manage/register/CmsRegisterController.java

@@ -139,7 +139,9 @@ public class CmsRegisterController {
     @PostMapping("/wx/refund")
     @SaCheckPermission("sign:refund")
     public Result<String> wxRefund(@RequestBody @Validated OrderRefundReq refundReq) throws Exception {
-        return registerOrderDonService.wxRefund(refundReq);
+        RegisterOrderDon registerOrderDon = registerOrderDonService.getById(refundReq.getOrderId());
+        if (registerOrderDon==null) throw BusinessRuntimeException.getInstance("");
+        return registerOrderDonService.wxRefund(refundReq, registerOrderDon);
     }
 
     /**
@@ -173,6 +175,15 @@ public class CmsRegisterController {
         }
     }
 
+    /**
+     * 注册 统一退款
+     */
+    @PostMapping("/unified/refund")
+    public Result<String> unifiedRefund(@RequestBody OrderRefundReq refundReq) throws Exception {
+        registerOrderDonService.unifiedRefund(refundReq);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
     /**
      * 获取需要解除限制的账号列表
      */

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

@@ -215,6 +215,7 @@ public class OrderController {
 	/**
      * 支付宝表单支付
 	 * 支付宝调起支付宝表单
+     * 手机支付
 	 */
 	@PostMapping("/post/pay/zfb")
     @Deprecated

+ 63 - 0
netflix-web/src/main/java/com/cyksj/web/controller/register/RegisterController.java

@@ -17,6 +17,8 @@ import com.cyksj.model.entity.Proxys;
 import com.cyksj.model.entity.RegisterOrderDon;
 import com.cyksj.model.entity.SpotifyUnLimitRecord;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.AlipayOrderDonReq;
+import com.cyksj.model.response.AliPayTradeStatus;
 import com.cyksj.model.views.AppleIdCountryOrAreaDataView;
 import com.cyksj.model.views.CouponUserView;
 import com.cyksj.service.register.RegisterOrderDonService;
@@ -34,7 +36,9 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.OutputStream;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author chan
@@ -122,6 +126,40 @@ public class RegisterController {
         }
     }
 
+    /**
+     * 支付宝支付
+     */
+    @PostMapping("/zfb/unified/pay")
+    public Result<String> zfbUnifiedPay(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+        if (re.getType() == null) throw BusinessRuntimeException.getInstance("支付异常");
+        String pay_body = registerOrderDonService.zfbUnifiedPay(re).getBody();
+//        response.setContentType("text/html;charset=" + BaseZfbConfig.charset);
+//        //直接将完整的表单html输出到页面
+//        response.getWriter().write(pay_body);
+//        response.getWriter().flush();
+//        response.getWriter().close();
+        return GatewayResponse.SUCCESS.newBuilder().toResult(pay_body);
+    }
+
+    /**
+     * 支付宝回调
+     */
+    @PostMapping("/prepay/zfb/notify")
+    public String aliPayNotify(HttpServletRequest request) throws Exception {
+        ////将异步通知中收到的所有参数都存放到map中
+        Map<String, String> params = convertRequestParamsToMap(request);
+        String tradeStatus = params.get("trade_status");
+        String orderNo = params.get("out_trade_no");
+        if (AliPayTradeStatus.TRADE_SUCCESS.getStatus().equals(tradeStatus) || AliPayTradeStatus.TRADE_FINISHED.getStatus().equals(tradeStatus)) {
+            log.info("支付宝商家订单号orderNo:{},status:{}开始回调", orderNo, tradeStatus);
+            registerOrderDonService.aliPayNotify(params);
+        } else {
+            log.error("支付宝回调 error 状态不符合 成功或完成 status:{} ,orderNo:{}", tradeStatus, orderNo);
+            return "fail";
+        }
+        return "success";
+    }
+
     @GetMapping("/get")
     public Result<SearchResult<RegisterOrderDon>> get(){
         long userId = StpUserUtil.getLoginIdAsLong();
@@ -209,4 +247,29 @@ public class RegisterController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(proxysMapper.selectPage(new Page<>(start, limit), Wrappers.lambdaQuery(Proxys.class).orderByDesc(Proxys::getScore)));
     }
 
+    /**
+     * 获取支付宝回调参数
+     */
+    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
+        Map<String, String> retMap = new HashMap<>();
+        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
+        for (Map.Entry<String, String[]> entry : entrySet) {
+            String name = entry.getKey();
+            String[] values = entry.getValue();
+            int valLen = values.length;
+            if (valLen == 1) {
+                retMap.put(name, values[0]);
+            } else if (valLen > 1) {
+                StringBuilder sb = new StringBuilder();
+                for (String val : values) {
+                    sb.append(",").append(val);
+                }
+                retMap.put(name, sb.substring(1));
+            } else {
+                retMap.put(name, "");
+            }
+        }
+        return retMap;
+    }
+
 }

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

@@ -9,6 +9,7 @@ import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayApiCode;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.RegisterOrderDonMapper;
 import com.cyksj.mapper.manage.coupon.CouponUserMapper;
 import com.cyksj.model.dto.UserWhoami;
 import com.cyksj.model.entity.*;
@@ -62,6 +63,8 @@ public class UserController {
 
     private final WorkOrderFrontService workOrderFrontService;
 
+    private final RegisterOrderDonMapper registerOrderDonMapper;
+
     private final HttpServletRequest request;
 
     private final CropChatService cropChatService;
@@ -94,7 +97,10 @@ public class UserController {
         UserPersonalView personalView = new UserPersonalView();
         DateTime now = DateTime.now();
         //车票
-        personalView.setNumOfTickets(ticket.size());
+        Integer register_count = registerOrderDonMapper.selectCount(Wrappers.lambdaQuery(RegisterOrderDon.class)
+                .eq(RegisterOrderDon::getUserId, userId)
+                .eq(RegisterOrderDon::getStatus, RegisterOrderDon.Status.complete));
+        personalView.setNumOfTickets(ticket.size() + register_count);
         //优惠券
         Integer couponSize = couponUserMapper.selectCount(Wrappers.lambdaQuery(CouponUser.class)
                 .eq(CouponUser::getUserId, userId)