diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardPayTypeEnum.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardPayTypeEnum.java index 1d054be0e..63bbb45b3 100644 --- a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardPayTypeEnum.java +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardPayTypeEnum.java @@ -24,6 +24,8 @@ public enum HardPayTypeEnum { RESERVE_QR_CODE("7", "线上二维码支付"), CASH("8", "现金支付"), HARD_DOOR_FREE_PAY("9", "智能柜免密支付"), + WECHANT_SELF_QR_CODE_PAY("10", "微信付款码支付"), + ALI_SELF_QR_CODE_PAY("11", "支付宝付款码支付"), ; private final String type; private final String description; @@ -36,7 +38,14 @@ public enum HardPayTypeEnum { CASH ); - public static final List isNotPay = List.of( + public static final List isNotWalletPay = List.of( + STRIDE_DEPT_QR_CODE, + FOREIGN_TICKET_QR_CODE, + WECHANT_SELF_QR_CODE_PAY, + ALI_SELF_QR_CODE_PAY + ); + + public static final List isNeedCancel = List.of( STRIDE_DEPT_QR_CODE, FOREIGN_TICKET_QR_CODE ); diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechantReverseDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechantReverseDto.java new file mode 100644 index 000000000..71e2ca977 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechantReverseDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.hard.api.dto.wechat; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 撤销订单入参 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WechantReverseDto { + + private Long orderId; + + private String wechantOrderId; + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatMicropayDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatMicropayDto.java new file mode 100644 index 000000000..cdcecd72b --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatMicropayDto.java @@ -0,0 +1,34 @@ +package com.bsd.pjcloud.hard.api.dto.wechat; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WechatMicropayDto { + + /** + * 商户id + */ + private Long merId; + + /** + * 订单id + */ + private Long orderId; + + /** + * 支付金额(分) + */ + private Integer price; + + /** + * 微信付款码code + */ + private String wechatQrCode; + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatQueryDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatQueryDto.java new file mode 100644 index 000000000..c3678e794 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatQueryDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.hard.api.dto.wechat; + +import lombok.Data; + +/** + * 查询订单入参 + */ +@Data +public class WechatQueryDto { + + /** + * 微信订单号 + */ + private String wechantOrderId; + + /** + * 商户订单号 + */ + private String orderId; + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatRefundDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatRefundDto.java new file mode 100644 index 000000000..837bc8152 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatRefundDto.java @@ -0,0 +1,27 @@ +package com.bsd.pjcloud.hard.api.dto.wechat; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 退款入参 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WechatRefundDto { + + private Long orderId; + + private String wechantOrderId; + + private Long refundId; + + private Integer orderPrice; + + private Integer refundPrice; + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatRefundQueryDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatRefundQueryDto.java new file mode 100644 index 000000000..b01d99737 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/wechat/WechatRefundQueryDto.java @@ -0,0 +1,17 @@ +package com.bsd.pjcloud.hard.api.dto.wechat; + +import lombok.Data; + +/** + * 微信退款查询入参 + */ +@Data +public class WechatRefundQueryDto { + + /** + * 退款id + */ + private String refundId; + + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantRefunCallbackSoureVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantRefunCallbackSoureVo.java new file mode 100644 index 000000000..8f0905354 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantRefunCallbackSoureVo.java @@ -0,0 +1,30 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import lombok.Data; + +/** + * 微信退款回调加密的返回参数 + */ +@Data +public class WechantRefunCallbackSoureVo { + + /** + * 公众账号ID + */ + private String appid; + + /** + * 退款的商户号 + */ + private String mch_id; + + /** + * 随机字符串 + */ + private String nonce_str; + + /** + * 加密信息 + */ + private String req_info; +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantRefunCallbackVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantRefunCallbackVo.java new file mode 100644 index 000000000..cf289e298 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantRefunCallbackVo.java @@ -0,0 +1,77 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 微信退款回调返回参数 + */ +@Data +public class WechantRefunCallbackVo { + + public static final String SUCCESS_CODE = "SUCCESS"; + + /** + * 微信订单号 + */ + private String transaction_id; + + /** + * 商户订单号 + */ + private String out_trade_no; + + /** + * 微信退款单号 + */ + private String refund_id; + + /** + * 商户退款单号 + */ + private String out_refund_no; + + /** + * 订单金额 + */ + private String total_fee; + + /** + * 应结订单金额 + */ + private String settlement_total_fee; + + /** + * 申请退款金额 + */ + private String refund_fee; + + /** + * 退款金额 + */ + private String settlement_refund_fee; + + /** + * 退款状态 + */ + private String refund_status; + + public boolean isAllSuccess() { + return ObjectUtil.equals(refund_status, SUCCESS_CODE); + } + + public static String wechantError() { + return "" + + "" + + "" + + ""; + } + + public static String wechantSuccess() { + return "" + + " " + + " \n" + + ""; + } + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantReverseVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantReverseVo.java new file mode 100644 index 000000000..b9bd73a5c --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechantReverseVo.java @@ -0,0 +1,44 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 撤销订单返回 + */ +@Data +public class WechantReverseVo { + public static final String SUCCESS = "SUCCESS"; + + private String return_code; + + private String return_msg; + + private String appid; + + private String mch_id; + + private String nonce_str; + + private String sign; + + private String result_code; + + private String err_code; + + private String err_code_des; + + private String recall; + + public boolean isHttpSucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, result_code); + } + + public boolean isAllSuccess() { + return isHttpSucess() && isPaySucess(); + } +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatMicropayVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatMicropayVo.java new file mode 100644 index 000000000..0c3878e6a --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatMicropayVo.java @@ -0,0 +1,43 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +@Data +public class WechatMicropayVo { + + public static final String SUCCESS = "SUCCESS"; + + private String return_code; + + private String return_msg; + + private String appid; + + private String mch_id; + + private String device_info; + + private String nonce_str; + + private String sign; + + private String result_code; + + private String err_code; + + private String err_code_des; + + public boolean isHttpSucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, result_code); + } + + public boolean isAllSuccess(){ + return isHttpSucess() && isPaySucess(); + } + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatQueryVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatQueryVo.java new file mode 100644 index 000000000..c4cd034b6 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatQueryVo.java @@ -0,0 +1,125 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 查询订单返回 + */ +@Data +public class WechatQueryVo { + public static final String SUCCESS = "SUCCESS"; + + private String return_code; + + private String return_msg; + + private String appid; + + private String mch_id; + + private String nonce_str; + + private String sign; + + private String result_code; + + private String err_code; + + private String err_code_des; + + private String device_info; + + /** + * 用户标识 + */ + private String openid; + + /** + * 是否关注公众账号 + */ + private String is_subscribe; + + /** + * 交易类型 + */ + private String trade_type; + + /** + * 交易状态 + */ + private String trade_state; + + /** + * 付款银行 + */ + private String bank_type; + + /** + * 标价金额 + */ + private String total_fee; + + /** + * 应结订单金额 + */ + private String settlement_total_fee; + + /** + * 标价币种 + */ + private String fee_type; + + /** + * 现金支付金额 + */ + private String cash_fee; + + /** + * 现金支付币种 + */ + private String cash_fee_type; + + /** + * 代金券金额 + */ + private String coupon_fee; + + /** + * 代金券使用数量 + */ + private String coupon_count; + + /** + * 微信支付订单号 + */ + private String transaction_id; + + /** + * 商户订单号 + */ + private String out_trade_no; + + /** + * 附加数据 + */ + private String attach; + + /** + * 支付完成时间 + */ + private String time_end; + + /** + * 交易状态描述 + */ + private String trade_state_desc; + + public boolean isHttpSucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, result_code); + } +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatRefundQueryVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatRefundQueryVo.java new file mode 100644 index 000000000..3479d177e --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatRefundQueryVo.java @@ -0,0 +1,102 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 退款返回 + */ +@Data +public class WechatRefundQueryVo { + + public static final String SUCCESS = "SUCCESS"; + + /** + * 业务结果 + */ + private String result_code; + + /** + * 错误码 + */ + private String err_code; + + /** + * 错误描述 + */ + private String err_code_des; + + /** + * 公众账号ID + */ + private String appid; + + /** + * 商户号 + */ + private String mch_id; + + /** + * 随机字符串 + */ + private String nonce_str; + + /** + * 签名 + */ + private String sign; + + /** + * 订单总退款次数 + */ + private Long total_refund_count; + + /** + * 微信订单号 + */ + private String transaction_id; + + /** + * 商户订单号 + */ + private String out_trade_no; + + /** + * 订单金额 + */ + private Long total_fee; + + /** + * 应结订单金额 + */ + private Long settlement_total_fee; + + /** + * 货币种类 + */ + private String fee_type; + + /** + * 现金支付金额 + */ + private Long cash_fee; + + /** + * 退款笔数 + */ + private Long refund_count; + + /** + * 退款总金额 + */ + private Long refund_fee; + + public boolean isHttpSucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, err_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, result_code); + } + +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatRefundVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatRefundVo.java new file mode 100644 index 000000000..4355502e7 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/wechat/WechatRefundVo.java @@ -0,0 +1,84 @@ +package com.bsd.pjcloud.hard.api.vo.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 退款返回 + */ +@Data +public class WechatRefundVo { + + public static final String SUCCESS = "SUCCESS"; + + private String return_code; + + private String return_msg; + + private String result_code; + + private String err_code; + + private String err_code_des; + + private String appid; + + private String mch_id; + + private String nonce_str; + + + private String sign; + + /** + * 微信支付订单号 + */ + private String transaction_id; + + /** + * 商户订单号 + */ + private String out_trade_no; + + /** + * 商户退款单号 + */ + private String out_refund_no; + + /** + * 微信退款单号 + */ + private String refund_id; + + /** + * 退款金额 + */ + private String refund_fee; + + /** + * 应结退款金额 + */ + private String settlement_refund_fee; + + /** + * 标价金额 + */ + private String total_fee; + + /** + * 应结订单金额 + */ + private String settlement_total_fee; + + public boolean isHttpSucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(WechatMicropayVo.SUCCESS, result_code); + } + + public boolean isAllSuccess() { + return isHttpSucess() && isPaySucess(); + } +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/config/WechatPay.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/config/WechatPay.java new file mode 100644 index 000000000..b201ed6bd --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/config/WechatPay.java @@ -0,0 +1,43 @@ +package com.bsd.pjcloud.hard.config; + + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "wechat-pay") +@Data +public class WechatPay { + + /** + * 基础路径 + */ + private String baseUrl; + + /** + * 微信公共平台 appId + */ + private String appId; + + /** + * 商户号 + */ + private String merchantId; + + /** + * 商户证书序列path + */ + private String merchantSerialPath; + + /** + * 商户APIV2密钥 + */ + private String apiV2Key; + + /** + * 退款回调地址 + */ + private String refundCallbackUrl; + +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardApptController.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardApptController.java index 20b43bbc2..68b73b41a 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardApptController.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardApptController.java @@ -22,7 +22,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.Objects; /** * 设备预约管理 diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardBroadcastController.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardBroadcastController.java index 990dc108b..e1f54df10 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardBroadcastController.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/HardBroadcastController.java @@ -2,7 +2,6 @@ package com.bsd.pjcloud.hard.controller; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.collection.CollUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum; @@ -26,7 +25,6 @@ import org.springframework.web.bind.annotation.*; import java.time.LocalDate; import java.util.List; -import java.util.Objects; /** * 设备广播 diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/wechant/WechantPayController.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/wechant/WechantPayController.java new file mode 100644 index 000000000..c96891b49 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/wechant/WechantPayController.java @@ -0,0 +1,40 @@ +package com.bsd.pjcloud.hard.controller.wechant; + +import com.bsd.pjcloud.common.security.annotation.Inner; +import com.bsd.pjcloud.hard.service.WechatPayService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/hard-wechant-pay") +@Tag(description = "hard-wechant", name = "微信相关") +@SecurityRequirement(name = HttpHeaders.AUTHORIZATION) +@Validated +public class WechantPayController { + + private final WechatPayService wechatPayService; + + /* ************************************* start callback start ************************************* */ + + @Inner(value = false) + @PostMapping("/callback/refund") + @Operation(summary = "微信退款回调") + public String refundCallback(HttpEntity httpEntity, @RequestHeader Map headers) { + return wechatPayService.refundCallback(httpEntity, headers); + } + + /* ************************************* end callback end ************************************* */ + +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardAfterSaleService.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardAfterSaleService.java index d6cd18b1b..19b9fc66f 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardAfterSaleService.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardAfterSaleService.java @@ -10,6 +10,7 @@ import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity; import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleLogEntity; import com.bsd.pjcloud.hard.api.vo.order.HardAfterSaleVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechantRefunCallbackVo; import java.util.List; @@ -43,6 +44,11 @@ public interface HardAfterSaleService extends IService { void refund(Long afterSaleId, String prefixStr); + /** + * 微信退款回调通知 + */ + boolean wechatRefundCallback(WechantRefunCallbackVo decrypt); + /** * 同意售后 */ diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderService.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderService.java index ec193b7b2..ba614d93b 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderService.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderService.java @@ -7,6 +7,8 @@ import com.bsd.pjcloud.admin.api.entity.SysUser; import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum; import com.bsd.pjcloud.common.data.datascope.DataScope; import com.bsd.pjcloud.common.security.service.PjcloudUser; +import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum; +import com.bsd.pjcloud.hard.api.constant.order.HardPayTypeEnum; import com.bsd.pjcloud.hard.api.dto.hard.HandCancelCodeDto; import com.bsd.pjcloud.hard.api.dto.hard.HardCreateOrderDto; import com.bsd.pjcloud.hard.api.dto.order.HardCreateCarDto; @@ -35,6 +37,9 @@ public interface HardOrderService extends IService { HardOrderVo join(Long id); + /** + * 创建订单 + */ Long createOrder(HardCreateOrderDto dto); /** @@ -63,10 +68,15 @@ public interface HardOrderService extends IService { Long cancelHardDoorOrder(Long orderId); /** - * 快速扣款,离线订单使用 + * 快速扣款 */ void fastReduceBalance(HardOrderEntity order); + /** + * 订单成功 + */ + void orderSuccess(HardOrderEntity order, Boolean isPay); + /** * 计算额外金额 */ @@ -98,4 +108,9 @@ public interface HardOrderService extends IService { * 创建订单后发送mq消息 */ void createOrderAfterSendMqMsg(Long orderId, UserInfo userInfo); + + /** + * 是否需要支付 + */ + boolean isPay(HardOrderTypeEnum type, HardPayTypeEnum payType); } \ No newline at end of file diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/WechatPayService.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/WechatPayService.java new file mode 100644 index 000000000..f2f85f0a6 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/WechatPayService.java @@ -0,0 +1,45 @@ +package com.bsd.pjcloud.hard.service; + + +import com.bsd.pjcloud.hard.api.dto.wechat.*; +import com.bsd.pjcloud.hard.api.vo.wechat.*; +import org.springframework.http.HttpEntity; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.util.Map; + +/** + * 微信支付 + */ +public interface WechatPayService { + + /** + * 付款码支付 + */ + WechatMicropayVo micropay(WechatMicropayDto dto); + + /** + * 查询订单 + */ + WechatQueryVo query(WechatQueryDto dto); + + /** + * 撤销订单 + */ + WechantReverseVo reverse(WechantReverseDto dto); + + /** + * 申请退款 + */ + WechatRefundVo refund(WechatRefundDto dto); + + /** + * 查询退款 + */ + WechatRefundQueryVo refundQuery(WechatRefundQueryDto dto); + + /** + * 退款回调 + */ + String refundCallback(HttpEntity httpEntity, @RequestHeader Map headers); +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardAfterSaleServiceImpl.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardAfterSaleServiceImpl.java index 9d684f1e2..73611f8c3 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardAfterSaleServiceImpl.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardAfterSaleServiceImpl.java @@ -21,6 +21,7 @@ import com.bsd.pjcloud.common.data.datascope.DataScope; import com.bsd.pjcloud.common.security.service.PjcloudUser; import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum; import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum; +import com.bsd.pjcloud.hard.api.constant.order.HardPayTypeEnum; import com.bsd.pjcloud.hard.api.constant.refund.HardAfterSaleOperateTypeEnum; import com.bsd.pjcloud.hard.api.constant.refund.HardRefundStatusEnum; import com.bsd.pjcloud.hard.api.constant.refund.HardSaleStatusEnum; @@ -29,18 +30,21 @@ import com.bsd.pjcloud.hard.api.dto.order.HardAdminRefundDto; import com.bsd.pjcloud.hard.api.dto.order.HardAfterSaleDto; import com.bsd.pjcloud.hard.api.dto.order.HardDisagreeDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; +import com.bsd.pjcloud.hard.api.dto.wechat.WechatRefundDto; import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity; import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleLogEntity; import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity; import com.bsd.pjcloud.hard.api.utils.HardUtil; import com.bsd.pjcloud.hard.api.vo.order.HardAfterSaleVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechantRefunCallbackVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechatRefundVo; import com.bsd.pjcloud.hard.mapper.order.HardAfterSaleLogMapper; import com.bsd.pjcloud.hard.mapper.order.HardAfterSaleMapper; import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper; import com.bsd.pjcloud.hard.service.HardAfterSaleService; import com.bsd.pjcloud.hard.service.HardOrderService; -import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayVoStatusEnum; +import com.bsd.pjcloud.hard.service.WechatPayService; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundDto; import com.bsd.pjcloud.wallet.api.feign.RemoteWalletRechargeService; import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeVo; @@ -57,9 +61,6 @@ import java.util.Map; /** * 售后订单 - * - * @author dzc - * @date 2025-01-07 17:23:08 */ @Validated @Slf4j @@ -71,6 +72,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl walletRefundResult = walletRechargeService.refund(hardRefundDto); - if (walletRefundResult.getCode() != 0 || ObjectUtil.isEmpty(walletRefundResult.getData())) { - throw new RuntimeException("钱包退款错误"); + HardOrderTypeEnum hardOrderType = HardOrderTypeEnum.valueOfByType(order.getOrderType()); + HardPayTypeEnum hardPayType = HardPayTypeEnum.valueOfByType(order.getPayType()); + // 是否钱包支付 + boolean isWalletPay = hardOrderService.isPay(hardOrderType, hardPayType); + // 是否微信支付 + boolean isWeChatPay = ObjectUtil.equals(order.getPayType(), HardPayTypeEnum.WECHANT_SELF_QR_CODE_PAY.getType()); + // 是否支付宝支付 + boolean isAliPay = ObjectUtil.equals(order.getPayType(), HardPayTypeEnum.ALI_SELF_QR_CODE_PAY.getType()); + if (isWalletPay) { + WalletRechargeRefundDto hardRefundDto = WalletRechargeRefundDto.builder().walletId(order.getWalletId()).orderId(order.getId()).afterSaleId(afterSale.getId()).refundCode(refundCode).reason("订单退款").price(refundPrice).build(); + R walletRefundResult = walletRechargeService.refund(hardRefundDto); + if (walletRefundResult.getCode() != 0 || ObjectUtil.isEmpty(walletRefundResult.getData())) { + throw new RuntimeException("钱包退款错误"); + } + WalletRechargeVo walletRefund = walletRefundResult.getData(); + HardOrderEntity updateObj = HardOrderEntity.builder() + .id(order.getId()) + .orderStatus(HardOrderStatusEnum.REFUND.getType()) + .refundStatus(HardRefundStatusEnum.SUCCESS.getStatus()) + .payRefundId(walletRefund.getId()) + .refundPrice(refundTotalPrice + refundPrice) + .refundTime(LocalDateTime.now()) + .build(); + hardOrderService.updateById(updateObj); + } else if (isWeChatPay) { + WechatRefundDto refundDto = WechatRefundDto.builder().orderId(order.getId()).refundId(afterSale.getId()).orderPrice(refundPrice).refundPrice(refundPrice).build(); + WechatRefundVo refundVo = wechatPayService.refund(refundDto); + if (ObjectUtil.isEmpty(refundVo)) { + throw new RuntimeException("微信退款错误"); + } + if (!refundVo.isAllSuccess()) { + throw new RuntimeException(refundVo.getErr_code_des()); + } + } else if (isAliPay) { + throw new RuntimeException("支付宝退款暂不支持"); + } + } + + /** + * 微信退款回调通知 + */ + @Override + public boolean wechatRefundCallback(WechantRefunCallbackVo decrypt) { + try { + Long orderId = Long.valueOf(decrypt.getOut_trade_no()); + Long refunId = Long.valueOf(decrypt.getOut_refund_no()); + // 查询订单 + HardOrderEntity order = hardOrderService.getById(orderId); + if (ObjectUtil.isEmpty(order)) { + log.error("微信退款回调通知,订单不存在orderId:{}", orderId); + return false; + } + // 查询售后单 + HardAfterSaleEntity afterSale = baseMapper.selectById(refunId); + if (ObjectUtil.isEmpty(afterSale)) { + log.error("微信退款回调通知,售后单不存在refunId:{}", refunId); + return false; + } + if (ObjectUtil.equals(afterSale.getStatus(), HardSaleStatusEnum.COMPLETE.getStatus())) { + log.error("微信退款回调通知,售后单已处理完成refunId:{}", refunId); + return false; + } + HardOrderEntity updateObj = HardOrderEntity.builder() + .id(order.getId()) + .orderStatus(HardOrderStatusEnum.REFUND.getType()) + .refundStatus(HardRefundStatusEnum.SUCCESS.getStatus()) + .payRefundId(orderId) + .refundPrice(Integer.valueOf(decrypt.getRefund_fee())) + .refundTime(LocalDateTime.now()) + .build(); + hardOrderService.updateById(updateObj); + return true; + } catch (Exception e) { + log.error("微信退款回调通知失败", e); + return false; } - WalletRechargeVo walletRefund = walletRefundResult.getData(); - HardOrderEntity updateObj = HardOrderEntity.builder() - .id(order.getId()) - .orderStatus(HardOrderStatusEnum.REFUND.getType()) - .refundStatus(HardRefundStatusEnum.SUCCESS.getStatus()) - .payRefundId(walletRefund.getId()) - .refundPrice(refundTotalPrice + refundPrice) - .refundTime(LocalDateTime.now()) - .build(); - hardOrderService.updateById(updateObj); } @Override diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java index 7b9becf98..a6f1cba06 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java @@ -34,6 +34,9 @@ import com.bsd.pjcloud.hard.api.dto.order.HardCreateCarDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; import com.bsd.pjcloud.hard.api.dto.order.app.HardAppCreateOrderDto; import com.bsd.pjcloud.hard.api.dto.spu.DeductionSpuStockDto; +import com.bsd.pjcloud.hard.api.dto.wechat.WechantReverseDto; +import com.bsd.pjcloud.hard.api.dto.wechat.WechatMicropayDto; +import com.bsd.pjcloud.hard.api.dto.wechat.WechatRefundDto; import com.bsd.pjcloud.hard.api.entity.HardApptEntity; import com.bsd.pjcloud.hard.api.entity.manager.HardManagerEntity; import com.bsd.pjcloud.hard.api.entity.order.HardCarEntity; @@ -45,6 +48,9 @@ import com.bsd.pjcloud.hard.api.vo.HardDoorFlowVo; import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo; import com.bsd.pjcloud.hard.api.vo.order.HardCarVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechantReverseVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechatMicropayVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechatRefundVo; import com.bsd.pjcloud.hard.mapper.manager.HardManagerMapper; import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper; import com.bsd.pjcloud.hard.service.*; @@ -105,6 +111,7 @@ public class HardOrderServiceImpl extends ServiceImpl walletResult = remoteWalletService.getWallet(dto.getUserId(), WalletTypeEnum.EAT); @@ -237,7 +248,7 @@ public class HardOrderServiceImpl extends ServiceImpl params) { + String apiKey = wechatPay.getApiV2Key(); + Map filtered = new TreeMap<>(); + for (Map.Entry entry : params.entrySet()) { + if (ObjectUtil.isEmpty(entry.getValue()) || ObjectUtil.equals("sign", entry.getKey())) { + continue; + } + filtered.put(entry.getKey(), String.valueOf(entry.getValue())); + } + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : filtered.entrySet()) { + sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + sb.append("key=").append(apiKey); + try { + String sign = DigestUtils.md5Hex(String.valueOf(sb)); + return sign.toUpperCase(); + } catch (Exception e) { + log.error("微信支付签名生成失败", e); + } + return ""; + } + + private WechantPayConstant.Api initApi(WechantPayConstant.Api api) { + api.setBaseUrl(wechatPay.getBaseUrl()); + return api; + } + + private String getNonceStr() { + int length = 32; + return RandomUtil.randomString(length); + } + + private SSLSocketFactory createSSLSocketFactory() throws Exception { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + FileInputStream certStream = new FileInputStream(wechatPay.getMerchantSerialPath()); + keyStore.load(certStream, wechatPay.getMerchantId().toCharArray()); + certStream.close(); + // 创建KeyManagerFactory + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, wechatPay.getMerchantId().toCharArray()); + // 创建TrustManagerFactory(信任所有证书) + TrustManager[] trustManagers = new TrustManager[]{ + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + } + }; + // 创建SSLContext + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom()); + return sslContext.getSocketFactory(); + } + + /** + * 解密回调信息解密 + */ + private WechantRefunCallbackVo decrypt(String xml) { + try { + WechantRefunCallbackSoureVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(xml)), WechantRefunCallbackSoureVo.class); + String reqInfo = vo.getReq_info(); + // 1 对加密串A做base64解码,得到加密串B + byte[] encryptedBytes = Base64.decode(reqInfo); + // 2 对商户key做md5,得到32位小写key + String md5Key = DigestUtils.md5Hex(wechatPay.getApiV2Key()).toLowerCase(); + // 3. AES-256-ECB 解密 + SecretKeySpec secretKey = new SecretKeySpec(md5Key.getBytes(StandardCharsets.UTF_8), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + byte[] decryptedBytes = cipher.doFinal(encryptedBytes); + String json = new String(decryptedBytes, StandardCharsets.UTF_8); + WechantRefunCallbackVo entity = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(json)), WechantRefunCallbackVo.class); + log.debug("解密回调信息,json|{}", JSONUtil.toJsonStr(entity)); + return entity; + } catch (Exception e) { + e.printStackTrace(); + log.error("解密回调信息解密异常", e); + return null; + } + } + + /** + * 付款码支付 + */ + @Override + public WechatMicropayVo micropay(WechatMicropayDto dto) { + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatPay.getAppId()); + // 商户号 + params.put("mch_id", wechatPay.getMerchantId()); + // 设备号-终端设备号(商户自定义,如门店编号) + params.put("device_info", dto.getMerId()); + // 随机字符串 + params.put("nonce_str", getNonceStr()); + // 签名 + params.put("sign", ""); + // 签名类型 + params.put("sign_type", "MD5"); + // 商品描述 + params.put("body", "小铺故事超市-超市"); + // 商户单号 + params.put("out_trade_no", dto.getOrderId()); + // 订单金额(分) + params.put("total_fee", dto.getPrice()); + // 终端IP + params.put("spbill_create_ip", "220.191.229.131"); + // 付款码 + params.put("auth_code", dto.getWechatQrCode()); + // 生成签名 + params.put("sign", generateSign(params)); + WechantPayConstant.Api api = initApi(WechantPayConstant.APY); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("付款码支付,json,xml|{}", res); + if (ObjectUtil.isEmpty(res)) { + log.error("付款码支付,res为空"); + return null; + } + WechatMicropayVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), WechatMicropayVo.class); + log.debug("付款码支付,json,res|{}", JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("付款码支付,异常", e); + return null; + } + } + + /** + * 查询订单 + */ + @Override + public WechatQueryVo query(WechatQueryDto dto) { + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatPay.getAppId()); + // 商户号 + params.put("mch_id", wechatPay.getMerchantId()); + // 微信订单号 + params.put("transaction_id", dto.getWechantOrderId()); + // 商户订单号 + params.put("out_trade_no", dto.getOrderId()); + // 随机字符串 + params.put("nonce_str", getNonceStr()); + // 签名 + params.put("sign", ""); + // 签名类型 + params.put("sign_type", "MD5"); + // 生成签名 + params.put("sign", generateSign(params)); + WechantPayConstant.Api api = initApi(WechantPayConstant.QUERY); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("查询订单,json,xml|{}", res); + if (ObjectUtil.isEmpty(res)) { + log.error("查询订单,res为空"); + return null; + } + WechatQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), WechatQueryVo.class); + log.debug("查询订单,json,res|{}", JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("查询订单,异常", e); + return null; + } + } + + /** + * 撤销订单 + */ + @Override + public WechantReverseVo reverse(WechantReverseDto dto) { + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatPay.getAppId()); + // 商户号 + params.put("mch_id", wechatPay.getMerchantId()); + // 微信订单号 + params.put("transaction_id", dto.getWechantOrderId()); + // 商户订单号 + params.put("out_trade_no", dto.getOrderId()); + // 随机字符串 + params.put("nonce_str", getNonceStr()); + // 签名 + params.put("sign", ""); + // 签名类型 + params.put("sign_type", "MD5"); + // 生成签名 + params.put("sign", generateSign(params)); + WechantPayConstant.Api api = initApi(WechantPayConstant.REVERSE); + api.setSslSocketFactory(createSSLSocketFactory()); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("撤销订单,json,xml|{}", res); + if (ObjectUtil.isEmpty(res)) { + log.error("撤销订单,res为空"); + return null; + } + WechantReverseVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), WechantReverseVo.class); + log.debug("撤销订单,json,res|{}", JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("撤销订单,异常", e); + return null; + } + } + + /** + * 申请退款 + */ + @Override + public WechatRefundVo refund(WechatRefundDto dto) { + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatPay.getAppId()); + // 商户号 + params.put("mch_id", wechatPay.getMerchantId()); + // 随机字符串 + params.put("nonce_str", getNonceStr()); + // 签名 + params.put("sign", ""); + // 签名类型 + params.put("sign_type", "MD5"); + // 微信支付订单号 + params.put("transaction_id", dto.getWechantOrderId()); + // 商户订单号 + params.put("out_trade_no", dto.getOrderId()); + // 商户退款单号 + params.put("out_refund_no", dto.getRefundId()); + // 订单金额 + params.put("total_fee", dto.getOrderPrice()); + // 退款金额 + params.put("refund_fee", dto.getRefundPrice()); + // 退款结果通知url + params.put("notify_url", wechatPay.getRefundCallbackUrl()); + // 生成签名 + params.put("sign", generateSign(params)); + WechantPayConstant.Api api = initApi(WechantPayConstant.REFUND); + api.setSslSocketFactory(createSSLSocketFactory()); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("申请退款,json,xml|{}", res); + if (ObjectUtil.isEmpty(res)) { + log.error("申请退款,res为空"); + return null; + } + WechatRefundVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), WechatRefundVo.class); + log.debug("申请退款,json,res|{}", JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("申请退款,异常", e); + return null; + } + } + + /** + * 查询退款 + */ + @Override + public WechatRefundQueryVo refundQuery(WechatRefundQueryDto dto) { + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatPay.getAppId()); + // 商户号 + params.put("mch_id", wechatPay.getMerchantId()); + // 随机字符串 + params.put("nonce_str", getNonceStr()); + // 签名 + params.put("sign", ""); + // 签名类型 + params.put("sign_type", "MD5"); + // 签名类型 + params.put("out_refund_no", dto.getRefundId()); + // 生成签名 + params.put("sign", generateSign(params)); + WechantPayConstant.Api api = initApi(WechantPayConstant.REFUND_QUERY); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("查询退款,json,xml|{}", res); + if (ObjectUtil.isEmpty(res)) { + log.error("查询退款,res为空"); + return null; + } + WechatRefundQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), WechatRefundQueryVo.class); + log.debug("查询退款,json,res|{}", JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("查询退款,异常", e); + return null; + } + } + + /** + * 退款回调 + */ + @Override + public String refundCallback(HttpEntity httpEntity, Map headers) { + String body = httpEntity.getBody(); + WechantRefunCallbackVo decrypt = decrypt(body); + if (ObjectUtil.isEmpty(decrypt)) { + // 告诉微信错误 + return WechantRefunCallbackVo.wechantError(); + } + boolean isSuccess = hardAfterSaleService.wechatRefundCallback(decrypt); + return isSuccess ? WechantRefunCallbackVo.wechantSuccess() : WechantRefunCallbackVo.wechantError(); + } +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/utils/constant/WechantPayConstant.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/utils/constant/WechantPayConstant.java new file mode 100644 index 000000000..551b87bca --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/utils/constant/WechantPayConstant.java @@ -0,0 +1,63 @@ +package com.bsd.pjcloud.hard.utils.constant; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpRequest; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.http.HttpMethod; + +import javax.net.ssl.SSLSocketFactory; + +/** + * 微信支付api + */ +public class WechantPayConstant { + + public static final Api APY = Api.builder().summary("付款码支付").url("/pay/micropay").method(HttpMethod.POST).isNeedCertificate(false).build(); + + public static final Api QUERY = Api.builder().summary("查询订单").url("/pay/orderquery").method(HttpMethod.POST).isNeedCertificate(false).build(); + + public static final Api REVERSE = Api.builder().summary("撤销订单").url("/secapi/pay/reverse").method(HttpMethod.POST).isNeedCertificate(true).build(); + + public static final Api REFUND = Api.builder().summary("申请退款").url("/secapi/pay/refund").method(HttpMethod.POST).isNeedCertificate(true).build(); + + public static final Api REFUND_QUERY = Api.builder().summary("查询退款").url("/pay/refundquery").method(HttpMethod.POST).isNeedCertificate(false).build(); + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + static public class Api { + + private String summary; + + private String baseUrl; + + private String url; + + private String fullUrl; + + private HttpMethod method; + + private boolean isNeedCertificate = false; + + private SSLSocketFactory sslSocketFactory; + + public HttpRequest getHttpRequest() { + String fullUrl = baseUrl + url; + HttpRequest req = switch (method.name()) { + case "GET" -> HttpRequest.get(fullUrl); + case "POST" -> HttpRequest.post(fullUrl); + default -> null; + }; + if (ObjectUtil.isNotEmpty(req) && ObjectUtil.isNotEmpty(sslSocketFactory) && isNeedCertificate) { + req.setSSLSocketFactory(sslSocketFactory); + } + return req; + } + + } + +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/application.yml b/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/application.yml index b0027050e..58e2aa349 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/application.yml +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/application.yml @@ -24,3 +24,11 @@ spring: # 第三方回调配置 # pay-callback: # lb-mch-id: 1919673632357584898 + +wechat-pay: + merchant-id: 1718803142 + api-v2-key: EDn3OfIZZFwyS9Obx73XgQ8NHt01piUa + app-id: wx4ec0210f4bf42f9f + base-url: https://api.mch.weixin.qq.com + refund-callback-url: https://rj4jv5rwqs.by.takin.cc/hard/hard-wechant-pay/callback/refund + merchant-serial-path: /Users/dengzhangchen/Desktop/backups/pay/cert/apiclient_cert.p12 diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/test/java/hard/com/bsd/pjcloud/hard/WechatPayTest.java b/pjcloud-hardware/pjcloud-hardware-biz/src/test/java/hard/com/bsd/pjcloud/hard/WechatPayTest.java new file mode 100644 index 000000000..bb5bfe763 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/test/java/hard/com/bsd/pjcloud/hard/WechatPayTest.java @@ -0,0 +1,56 @@ +package hard.com.bsd.pjcloud.hard; + +import cn.hutool.json.JSONUtil; +import com.bsd.pjcloud.hard.HardApp; +import com.bsd.pjcloud.hard.api.dto.wechat.WechatMicropayDto; +import com.bsd.pjcloud.hard.api.dto.wechat.WechatQueryDto; +import com.bsd.pjcloud.hard.api.dto.wechat.WechatRefundDto; +import com.bsd.pjcloud.hard.api.vo.wechat.WechatMicropayVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechatQueryVo; +import com.bsd.pjcloud.hard.api.vo.wechat.WechatRefundVo; +import com.bsd.pjcloud.hard.service.WechatPayService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * 微信支付配置 + */ +@Slf4j +@SpringBootTest(classes = HardApp.class) +public class WechatPayTest { + + @Resource + private WechatPayService wechatPayService; + + @Test + public void micropay() throws Exception { + long currentTimeMillis = System.currentTimeMillis(); + + WechatMicropayDto dto = new WechatMicropayDto(); + dto.setMerId(currentTimeMillis); + dto.setOrderId(currentTimeMillis); + dto.setPrice(1); + dto.setWechatQrCode("132796932599913148"); + + WechatMicropayVo micropay = wechatPayService.micropay(dto); + if (micropay.isAllSuccess()) { + log.info("支付成功json:{}", JSONUtil.toJsonStr(micropay)); + } + } + + @Test + public void query() throws Exception { + WechatQueryDto dto = new WechatQueryDto(); + dto.setWechantOrderId("4200002719202506059568204561"); + + WechatQueryVo micropay = wechatPayService.query(dto); + } + + @Test + public void rerfund() throws Exception { + String currentOrderId = "4200002648202506062041165177"; + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml index 4355abcd2..ebc2867aa 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml @@ -131,6 +131,12 @@ com.bsd pjcloud-common-idempotent + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + com.bsd pjcloud-hardware-api diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/doc/第三方支付文档.wps b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/doc/第三方支付文档.wps index a8d465388..f6e3916d1 100644 Binary files a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/doc/第三方支付文档.wps and b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/doc/第三方支付文档.wps differ diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/PayTest.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/PayTest.java index 3ea4a9c5a..1d5fbfee3 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/PayTest.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/PayTest.java @@ -29,8 +29,8 @@ import java.util.Map; @SpringBootTest(classes = ThirdPartyApp.class) public class PayTest { - // private final String baseUrl = "http://123.156.230.15:8089/api"; - private final String baseUrl = "http://127.0.0.1:9999"; + private final String baseUrl = "http://123.156.230.15:8089/api"; + // private final String baseUrl = "http://127.0.0.1:9999"; private final String walletInfoUrl = "/third/third-pay-api/user-wallet"; @@ -80,7 +80,7 @@ public class PayTest { Map paramsMap = new HashMap<>(); paramsMap.put("userId", 1875049673022279681L); paramsMap.put("thirdOrderId", System.currentTimeMillis()); - paramsMap.put("price", 800); + paramsMap.put("price", 900); paramsMap.put("products", null); String body = JSONUtil.toJsonStr(paramsMap); // 发送请求 @@ -119,7 +119,7 @@ public class PayTest { public void walletRefund() throws Exception { ThirdKeyManageEntity config = getLbConfig(); Map paramsMap = new HashMap<>(); - paramsMap.put("platformOrderId", "1928048358927982594"); + paramsMap.put("platformOrderId", "1928337501121765377"); paramsMap.put("thirdRefundId", System.currentTimeMillis()); paramsMap.put("price", "300"); String body = JSONUtil.toJsonStr(paramsMap); @@ -152,7 +152,7 @@ public class PayTest { public void detail() throws Exception { ThirdKeyManageEntity config = getLbConfig(); Map paramsMap = new HashMap<>(); - paramsMap.put("thirdOrderId", "1748517531534"); + paramsMap.put("thirdOrderId", "1748586470745"); paramsMap.put("thirdRefundId", ""); String body = JSONUtil.toJsonStr(paramsMap); // 发送请求