diff --git a/src/main/java/com/sczx/pay/controller/AlipayRentNotifyController.java b/src/main/java/com/sczx/pay/controller/AlipayRentNotifyController.java index 2cb59f7..b113bb0 100644 --- a/src/main/java/com/sczx/pay/controller/AlipayRentNotifyController.java +++ b/src/main/java/com/sczx/pay/controller/AlipayRentNotifyController.java @@ -1,13 +1,84 @@ package com.sczx.pay.controller; +import com.sczx.pay.service.AlipayRentService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + @Api(value = "支付宝租赁订单回调接口", tags = "支付宝租赁订单回调接口") @Slf4j @RestController @RequestMapping("/alipay/rent/notify") public class AlipayRentNotifyController { + + @Autowired + private AlipayRentService alipayRentService; + + /** + * 支付宝租赁订单支付结果通知 + */ + @ApiOperation(value = "支付宝租赁订单支付结果通知") + @PostMapping("/pay") + public String alipayNotify(HttpServletRequest request) { + try { + // 读取支付宝回调数据 + Map params = new HashMap<>(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = iter.next(); + String[] values = requestParams.get(name); + String valueStr = ""; + for (int i = 0; i < values.length; i++) { + valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; + } + params.put(name, valueStr); + } + + String outTradeNo = params.get("out_trade_no"); + String companyIdStr = params.get("passback_params"); // 通过回传参数获取公司ID + Long companyId = companyIdStr != null ? Long.parseLong(companyIdStr) : null; + + log.info("收到支付宝租赁订单支付通知,数据: {}, 商户订单号: {}", params, outTradeNo); + + // 验证签名 +// if (!alipayService.verifyNotifySign(companyId, params)) { +// log.warn("支付宝支付通知签名验证失败,公司ID: {}", companyId); +// return buildResponse("failure"); +// } + + String tradeStatus = params.get("trade_status"); + if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)) { + log.warn("支付宝支付通知状态失败,商户订单号: {}: {}", outTradeNo, tradeStatus); + return "success"; // 状态不是成功时也返回success,避免重复通知 + } + + // 处理支付成功的业务逻辑 + String tradeNo = params.get("trade_no"); + String totalAmount = params.get("total_amount"); + + // 更新数据库中的订单状态 + boolean success = alipayRentService.processPaySuccessNotify(params); + if (success) { + log.info("支付宝支付成功,公司ID: {}, 订单号: {}, 支付宝交易号: {}, 金额: {}", + companyId, outTradeNo, tradeNo, totalAmount); + return "success"; + } else { + log.error("更新支付宝支付状态失败,公司ID: {}, 订单号: {}", companyId, outTradeNo); + return "failure"; + } + + } catch (Exception e) { + log.error("处理支付宝支付通知异常", e); + return "failure"; + } + } } diff --git a/src/main/java/com/sczx/pay/dto/ali/rent/AlipayRentPayReq.java b/src/main/java/com/sczx/pay/dto/ali/rent/AlipayRentPayReq.java new file mode 100644 index 0000000..b1cf623 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/ali/rent/AlipayRentPayReq.java @@ -0,0 +1,13 @@ +package com.sczx.pay.dto.ali.rent; + +import io.swagger.annotations.ApiModel; +import lombok.Data; + +@ApiModel(value = "支付宝租赁订单支付请求") +@Data +public class AlipayRentPayReq { + private Long companyId; // 公司ID + private String outTradeNo; // 商户订单号 + private String orderId; //交易组件业务订单号 + private String payAmount; // 支付金额 +} diff --git a/src/main/java/com/sczx/pay/dto/ali/rent/AlipayRentPayResponse.java b/src/main/java/com/sczx/pay/dto/ali/rent/AlipayRentPayResponse.java new file mode 100644 index 0000000..a19e567 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/ali/rent/AlipayRentPayResponse.java @@ -0,0 +1,17 @@ +package com.sczx.pay.dto.ali.rent; + +import com.sczx.pay.dto.AlipayResponse; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@ApiModel(value = "支付宝租赁订单支付结果") +@Data +public class AlipayRentPayResponse extends AlipayResponse { + + private String tradeNo; // 支付宝交易号 + private String outTradeNo; // 商户订单号 + private String orderId; //交易组件业务订单号 + private String payAmount; // 支付金额 +} diff --git a/src/main/java/com/sczx/pay/entity/PaymentRecord.java b/src/main/java/com/sczx/pay/entity/PaymentRecord.java index 549bc2e..7b4a3fd 100644 --- a/src/main/java/com/sczx/pay/entity/PaymentRecord.java +++ b/src/main/java/com/sczx/pay/entity/PaymentRecord.java @@ -14,6 +14,7 @@ public class PaymentRecord { private BigDecimal totalFee; // 订单金额 private String body; // 商品描述 private String openid; // 用户标识(微信支付专用) + private String tradeCompOrderId; // 支付宝交易组件订单号 private String tradeState; // 交易状态 private String tradeStateDesc; // 交易状态描述 private Date createTime; // 创建时间 @@ -26,7 +27,8 @@ public class PaymentRecord { // 支付渠道枚举 public enum PayChannel { WECHAT("微信支付"), - ALIPAY("支付宝"); + ALIPAY("支付宝"), + ALIPAY_RENT("支付宝租赁支付"); private final String description; @@ -164,4 +166,12 @@ public class PaymentRecord { public void setBuyerId(String buyerId) { this.buyerId = buyerId; } + + public String getTradeCompOrderId() { + return tradeCompOrderId; + } + + public void setTradeCompOrderId(String tradeCompOrderId) { + this.tradeCompOrderId = tradeCompOrderId; + } } diff --git a/src/main/java/com/sczx/pay/service/AlipayRentService.java b/src/main/java/com/sczx/pay/service/AlipayRentService.java index 07fb334..b04eeb8 100644 --- a/src/main/java/com/sczx/pay/service/AlipayRentService.java +++ b/src/main/java/com/sczx/pay/service/AlipayRentService.java @@ -1,4 +1,23 @@ package com.sczx.pay.service; +import com.sczx.pay.dto.ali.rent.AlipayRentPayReq; +import com.sczx.pay.dto.ali.rent.AlipayRentPayResponse; + +import java.util.Map; + public interface AlipayRentService { + + /** + * 租赁订单支付 + * @param request + * @return + */ + AlipayRentPayResponse rentPay(AlipayRentPayReq request); + + /** + * 支付成功回调 + * @param notifyMap + * @return + */ + boolean processPaySuccessNotify(Map notifyMap); } diff --git a/src/main/java/com/sczx/pay/service/impl/AlipayRentServiceImpl.java b/src/main/java/com/sczx/pay/service/impl/AlipayRentServiceImpl.java index e7bec93..fe9855d 100644 --- a/src/main/java/com/sczx/pay/service/impl/AlipayRentServiceImpl.java +++ b/src/main/java/com/sczx/pay/service/impl/AlipayRentServiceImpl.java @@ -1,10 +1,194 @@ package com.sczx.pay.service.impl; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.AlipayCommerceRentOrderPayModel; +import com.alipay.api.domain.RentPayItemDTO; +import com.alipay.api.request.AlipayCommerceRentOrderPayRequest; +import com.alipay.api.response.AlipayCommerceRentOrderPayResponse; +import com.sczx.pay.config.AlipayConf; +import com.sczx.pay.dto.ali.rent.AlipayRentPayReq; +import com.sczx.pay.dto.ali.rent.AlipayRentPayResponse; +import com.sczx.pay.entity.OrderMain; +import com.sczx.pay.entity.PayStatus; +import com.sczx.pay.entity.PaymentRecord; +import com.sczx.pay.mapper.OrderPayMapper; +import com.sczx.pay.mapper.PaymentRecordMapper; +import com.sczx.pay.mapper.RefundRecordMapper; import com.sczx.pay.service.AlipayRentService; +import com.sczx.pay.utils.AlipaySdkUtil; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + @Slf4j @Service public class AlipayRentServiceImpl implements AlipayRentService { + + @Autowired + private AlipayConf alipayConf; + + @Autowired + private AlipaySdkUtil alipaySdkUtil; + + @Value("${alipay.rent.payNotifyUrl}") + private String notifyUrl; + + @Autowired + private PaymentRecordMapper paymentRecordMapper; + + + @Autowired + private RefundRecordMapper refundRecordMapper; + + @Autowired + private OrderPayMapper orderPayMapper; + + @Override + public AlipayRentPayResponse rentPay(AlipayRentPayReq alipayRentPayReq) { + AlipayRentPayResponse response = new AlipayRentPayResponse(); + try { + // 构造请求参数以调用接口 + AlipayCommerceRentOrderPayRequest request = new AlipayCommerceRentOrderPayRequest(); + AlipayCommerceRentOrderPayModel model = new AlipayCommerceRentOrderPayModel(); + + // 设置租金支付外部请求号 + model.setOutTradeNo(alipayRentPayReq.getOutTradeNo()); + + // 设置业务订单号 + model.setOrderId(alipayRentPayReq.getOrderId()); + + // 设置支付方式,pay_method还可以选择:PRE_AUTH 预授权支付。部分支付场景不可使用租赁代扣 RENT_DEDUCT + model.setPayMethod("JSAPI"); + + // 设置支付金额 + model.setPayAmount(alipayRentPayReq.getPayAmount()); + + // 设置订单费用项明细列表 + List payItems = new ArrayList(); + RentPayItemDTO payItems0 = new RentPayItemDTO(); + payItems0.setType("RENT"); + payItems0.setPayAmount(alipayRentPayReq.getPayAmount()); + payItems.add(payItems0); + model.setPayItems(payItems); + + //二级商户信息 +// RentSubMerchantDTO rentSubMerchantDTO = new RentSubMerchantDTO(); +// rentSubMerchantDTO.setMerchantId(alipayConf.getCompanyAppid(alipayRentPayReq.getCompanyId())); +// model.setSubMerchant(rentSubMerchantDTO); + + // 设置支付结果通知地址 + model.setPayNotifyUrl(notifyUrl); + + // 设置支付超时时间 + model.setPayTimeoutExpress("15m"); + + request.setBizModel(model); + + // 第三方代调用模式下请设置app_auth_token + // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); + + + + // 第三方代调用模式下请设置app_auth_token + // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); + log.info("支付宝租赁订单下单请求:{}", JSONObject.toJSONString(request)); + AlipayCommerceRentOrderPayResponse rentOrderPayResponse = alipaySdkUtil.execute(request); + log.info("支付宝租赁订单下单下单返回:{}", JSONObject.toJSONString(rentOrderPayResponse)); + if (rentOrderPayResponse.isSuccess()) { + response.setSuccess(true); + response.setOutTradeNo(rentOrderPayResponse.getOutTradeNo()); + response.setTradeNo(rentOrderPayResponse.getTradeNo()); + response.setCode("SUCCESS"); + response.setMessage("下单成功"); + //保存支付单 + recordPaymentInfo(alipayRentPayReq); + + } else { + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("下单失败: " + rentOrderPayResponse.getMsg() + ":" + rentOrderPayResponse.getSubMsg()); + } + } catch (Exception e) { + log.error("支付宝下单异常,公司ID: {}, 订单号: {}", alipayRentPayReq.getCompanyId(), alipayRentPayReq.getOutTradeNo(), e); + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("下单异常: " + e.getMessage()); + } + + return response; + } + + @Override + public boolean processPaySuccessNotify(Map notifyMap) { + try { + // 这里实现您的业务逻辑 + // 例如:更新订单状态、发送通知等 + + String outTradeNo = notifyMap.get("out_trade_no"); + String tradeNo = notifyMap.get("trade_no"); + String totalAmount = notifyMap.get("total_amount"); + + log.info("处理支付宝租赁订单支付成功通知,订单号: {}, 交易号: {}, 金额: {}", + outTradeNo, tradeNo, totalAmount); + + // 更新支付记录状态 + int updated = paymentRecordMapper.updateToSuccess( + outTradeNo, + tradeNo, + new Date(), // 支付时间 + new Date() // 更新时间 + ); + if (updated > 0) { + log.info("支付宝支付记录状态已更新,订单号: {}, 支付宝交易号: {}", outTradeNo, tradeNo); + //更新主订单状态 + OrderMain orderMain = orderPayMapper.getOrderStatusByOrderNo(outTradeNo); + String OrderStatus = orderMain.getOrderStatus(); + + if(OrderStatus.equals("WAIT_PAY")){ + orderPayMapper.updateOrderStatus(orderMain.getOrderNo(),"WAIT_PICK"); + }else if (OrderStatus.equals("RERENT_WAIT_PAY")){ + orderPayMapper.updateOrderStatus(orderMain.getOrderNo(),"RENT_ING"); + } + orderPayMapper.updateSubOrderPaymentStatus(outTradeNo,"ZFB_PAY", PayStatus.SUCCESS.getCode(),tradeNo); + return true; + } else { + log.warn("未找到对应的支付宝支付记录,订单号: {}", outTradeNo); + return false; + } + } catch (Exception e) { + log.error("处理支付宝支付成功通知异常", e); + return false; + } + } + + /** + * 记录支付信息到数据库 + */ + private void recordPaymentInfo(AlipayRentPayReq alipayRentPayReq) { + try { + PaymentRecord paymentRecord = new PaymentRecord(); + paymentRecord.setCompanyId(alipayRentPayReq.getCompanyId()); + paymentRecord.setOutTradeNo(alipayRentPayReq.getOutTradeNo()); + paymentRecord.setTotalFee(new BigDecimal(alipayRentPayReq.getPayAmount())); // 转换为元 + paymentRecord.setTradeCompOrderId(alipayRentPayReq.getOrderId()); + paymentRecord.setTradeState("NOTPAY"); // 未支付 + paymentRecord.setTradeStateDesc("未支付"); + paymentRecord.setCreateTime(new Date()); + paymentRecord.setUpdateTime(new Date()); +// paymentRecord.setAttach(request.getAttach()); + paymentRecord.setPayChannel(PaymentRecord.PayChannel.ALIPAY_RENT.name()); // 设置支付渠道为支付宝支付 + + paymentRecordMapper.insertPaymentRecord(paymentRecord); + log.info("支付记录已保存,订单号: {}", alipayRentPayReq.getOutTradeNo()); + } catch (Exception e) { + log.error("保存支付记录异常,订单号: {}", alipayRentPayReq.getOutTradeNo(), e); + } + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ed915f9..e585e21 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -91,3 +91,6 @@ alipay: alipay-root-cert-path: /root/cert/alipayRootCert.crt notify-url: http://115.190.8.52:8019/alipay/pay/notify refund-notify-url: http://115.190.8.52:8019/alipay/refund/notify + + rent: + payNotifyUrl: http://115.190.8.52:8019/alipay/rent/notify/pay