diff --git a/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/dto/AppAdminSyncDto.java b/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/dto/AppAdminSyncDto.java new file mode 100644 index 000000000..5fa6a49b3 --- /dev/null +++ b/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/dto/AppAdminSyncDto.java @@ -0,0 +1,19 @@ +package com.bsd.pjcloud.app.api.dto; + +import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum; +import lombok.Data; + +@Data +public class AppAdminSyncDto { + + private String uniqueCode; + + private AppUserTypeEnum userTypeEnum; + + private Long adminUserId; + + private String username; + + private String avatarImage; + +} diff --git a/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/feign/RemoteAppUserService.java b/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/feign/RemoteAppUserService.java index a760e3321..9c336d666 100644 --- a/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/feign/RemoteAppUserService.java +++ b/pjcloud-app-server/pjcloud-app-server-api/src/main/java/com/bsd/pjcloud/app/api/feign/RemoteAppUserService.java @@ -19,6 +19,7 @@ package com.bsd.pjcloud.app.api.feign; +import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto; import com.bsd.pjcloud.app.api.dto.AppUserInfo; import com.bsd.pjcloud.common.core.constant.ServiceNameConstants; import com.bsd.pjcloud.common.core.util.R; @@ -26,6 +27,8 @@ import com.bsd.pjcloud.common.feign.annotation.NoToken; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; @FeignClient(contextId = "remoteAppUserService", value = ServiceNameConstants.APP_SERVER) @@ -49,5 +52,10 @@ public interface RemoteAppUserService { @GetMapping("/appsocial/info/{inStr}") R social(@PathVariable("inStr") String inStr); - + /** + * 同步admin账户信息为app账户 + */ + @NoToken + @PostMapping("/appsocial/info/sync-admin-account-info") + R syncAdminAccountInfo(@RequestBody AppAdminSyncDto appAdminSyncDto); } diff --git a/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/controller/AppSocialDetailsController.java b/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/controller/AppSocialDetailsController.java index dcd17e4e7..9d0b17a1b 100644 --- a/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/controller/AppSocialDetailsController.java +++ b/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/controller/AppSocialDetailsController.java @@ -20,6 +20,8 @@ package com.bsd.pjcloud.app.controller; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto; +import com.bsd.pjcloud.app.api.dto.AppUserInfo; import com.bsd.pjcloud.app.api.entity.AppSocialDetails; import com.bsd.pjcloud.app.service.AppSocialDetailsService; import com.bsd.pjcloud.common.core.util.R; @@ -49,6 +51,19 @@ public class AppSocialDetailsController { private final AppSocialDetailsService appSocialDetailsService; + /* ************************************* start 设备端 start ************************************* */ + + /** + * 同步admin账户信息为app账户 + */ + @PostMapping("/sync-admin-account-info") + public R syncAdminAccountInfo(@RequestBody AppAdminSyncDto dto) { + return R.ok(appSocialDetailsService.syncAdminAccountInfo(dto)); + } + + /* ************************************* end 设备端 end ************************************* */ + + /** * 社交登录账户简单分页查询 */ diff --git a/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/AppSocialDetailsService.java b/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/AppSocialDetailsService.java index 390ae7a22..5518483d8 100644 --- a/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/AppSocialDetailsService.java +++ b/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/AppSocialDetailsService.java @@ -18,30 +18,28 @@ package com.bsd.pjcloud.app.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto; import com.bsd.pjcloud.app.api.dto.AppUserInfo; import com.bsd.pjcloud.app.api.entity.AppSocialDetails; /** * 系统社交登录账号表 - * - * @author pjcloud - * @date 2018-08-16 21:30:41 */ public interface AppSocialDetailsService extends IService { - /** - * 绑定社交账号 - * @param state 类型 - * @param code code - * @return - */ - Boolean bindSocial(String state, String code); - /** - * 根据入参查询用户信息 - * @param inStr - * @return - */ - AppUserInfo getUserInfo(String inStr); + /** + * 同步admin账户信息为app账户 + */ + AppUserInfo syncAdminAccountInfo(AppAdminSyncDto dto); + /** + * 绑定社交账号 + */ + Boolean bindSocial(String state, String code); + + /** + * 根据入参查询用户信息 + */ + AppUserInfo getUserInfo(String inStr); } diff --git a/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/impl/AppSocialDetailsServiceImpl.java b/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/impl/AppSocialDetailsServiceImpl.java index e8e53dc61..a5163ef1a 100644 --- a/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/impl/AppSocialDetailsServiceImpl.java +++ b/pjcloud-app-server/pjcloud-app-server-biz/src/main/java/com/bsd/pjcloud/app/service/impl/AppSocialDetailsServiceImpl.java @@ -17,8 +17,12 @@ package com.bsd.pjcloud.app.service.impl; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum; +import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto; import com.bsd.pjcloud.app.api.dto.AppUserInfo; import com.bsd.pjcloud.app.api.entity.AppSocialDetails; import com.bsd.pjcloud.app.api.entity.AppUser; @@ -26,6 +30,7 @@ import com.bsd.pjcloud.app.handler.LoginHandler; import com.bsd.pjcloud.app.mapper.AppSocialDetailsMapper; import com.bsd.pjcloud.app.mapper.AppUserMapper; import com.bsd.pjcloud.app.service.AppSocialDetailsService; +import com.bsd.pjcloud.app.service.AppUserService; import com.bsd.pjcloud.common.core.constant.CacheConstants; import com.bsd.pjcloud.common.security.util.SecurityUtils; import lombok.AllArgsConstructor; @@ -42,45 +47,62 @@ import java.util.Map; @Slf4j @AllArgsConstructor @Service("appSocialDetailsService") -public class AppSocialDetailsServiceImpl extends ServiceImpl - implements AppSocialDetailsService { +public class AppSocialDetailsServiceImpl extends ServiceImpl implements AppSocialDetailsService { - private final Map loginHandlerMap; + private final Map loginHandlerMap; - private final CacheManager cacheManager; + private final CacheManager cacheManager; - private final AppUserMapper appUserMapper; + private final AppUserMapper appUserMapper; - /** - * 绑定社交账号 - * @param type type - * @param code code - * @return - */ - @Override - public Boolean bindSocial(String type, String code) { - LoginHandler loginHandler = loginHandlerMap.get(type); - // 绑定逻辑 - String identify = loginHandler.identify(code); - AppUser user = appUserMapper.selectById(SecurityUtils.getUser().getId()); - loginHandler.bind(user, identify); + private final AppUserService appUserService; - // 更新緩存 - cacheManager.getCache(CacheConstants.USER_DETAILS_MINI).evict(user.getUsername()); - return Boolean.TRUE; - } + @Override + public AppUserInfo syncAdminAccountInfo(AppAdminSyncDto dto) { + AppUser user = appUserService.getOne(Wrappers.query().lambda() + .eq(AppUser::getOpenid, dto.getUniqueCode()) + .eq(AppUser::getUserType, dto.getUserTypeEnum().getType()) + ); + if (ObjectUtil.isNotEmpty(user)) { + return appUserService.findUserInfo(user); + } + AppUser appUser = new AppUser(); + appUser.setOpenid(dto.getUniqueCode()); + appUser.setUserType(AppUserTypeEnum.MINI_ALIPAY.getType()); + appUser.setUsername(dto.getUsername()); + appUser.setName(dto.getUsername()); + appUser.setAvatar(dto.getAvatarImage()); + appUser.setCreateBy(dto.getUniqueCode()); + appUser.setUpdateBy(dto.getUniqueCode()); + appUserService.saveOrUpdate(appUser); + return appUserService.findUserInfo(user); + } - /** - * 根据入参查询用户信息 - * @param inStr TYPE@code - * @return - */ - @Override - public AppUserInfo getUserInfo(String inStr) { - String[] inStrs = inStr.split(StringPool.AT); - String type = inStrs[0]; - String loginStr = inStr.substring(type.length() + 1); - return loginHandlerMap.get(type).handle(loginStr); - } + /** + * 绑定社交账号 + */ + @Override + public Boolean bindSocial(String type, String code) { + LoginHandler loginHandler = loginHandlerMap.get(type); + // 绑定逻辑 + String identify = loginHandler.identify(code); + AppUser user = appUserMapper.selectById(SecurityUtils.getUser().getId()); + loginHandler.bind(user, identify); + + // 更新緩存 + cacheManager.getCache(CacheConstants.USER_DETAILS_MINI).evict(user.getUsername()); + return Boolean.TRUE; + } + + /** + * 根据入参查询用户信息 + */ + @Override + public AppUserInfo getUserInfo(String inStr) { + String[] inStrs = inStr.split(StringPool.AT); + String type = inStrs[0]; + String loginStr = inStr.substring(type.length() + 1); + return loginHandlerMap.get(type).handle(loginStr); + } } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformTypeEnum.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformTypeEnum.java index 687d79fde..df9b4c697 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformTypeEnum.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformTypeEnum.java @@ -14,7 +14,7 @@ import java.util.Arrays; @Getter public enum MiniPlatformTypeEnum { - WECAHT("10", "微信小程序"), + WECHAT("10", "微信小程序"), ALI_PAY("20", "支付宝"), ; diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMinAppOAth2LoginDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMiniAppGetUniqueDto.java similarity index 82% rename from pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMinAppOAth2LoginDto.java rename to pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMiniAppGetUniqueDto.java index 8ed30913d..cd8dce3b8 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMinAppOAth2LoginDto.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMiniAppGetUniqueDto.java @@ -6,7 +6,7 @@ import jakarta.validation.constraints.NotNull; import lombok.Data; @Data -public class ThirdMinAppOAth2LoginDto { +public class ThirdMiniAppGetUniqueDto { /** * 小程序平台 @@ -17,4 +17,9 @@ public class ThirdMinAppOAth2LoginDto { @NotEmpty(message = "code不能为空") private String code; + /** + * 用户id + */ + private Long userId; + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMiniAppOAth2LoginDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMiniAppOAth2LoginDto.java new file mode 100644 index 000000000..f69578c27 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/ThirdMiniAppOAth2LoginDto.java @@ -0,0 +1,23 @@ +package com.bsd.pjcloud.thirdparty.dto.oathmini; + +import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class ThirdMiniAppOAth2LoginDto { + + /** + * 小程序平台 + */ + @NotNull(message = "小程序平台标识不能为空") + private MiniPlatformTypeEnum miniPlatformType; + + @NotEmpty(message = "phoneCode不能为空") + private String phoneCode; + + @NotEmpty(message = "userCode不能为空") + private String userCode; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechantReverseDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechantReverseDto.java new file mode 100644 index 000000000..502c64378 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechantReverseDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 撤销订单入参 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ThirdMiniWechantReverseDto { + + private Long orderId; + + private String wechantOrderId; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatQueryDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatQueryDto.java new file mode 100644 index 000000000..fdbf6ba40 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatQueryDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat; + +import lombok.Data; + +/** + * 查询订单入参 + */ +@Data +public class ThirdMiniWechatQueryDto { + + /** + * 微信订单号 + */ + private String wechantOrderId; + + /** + * 商户订单号 + */ + private String orderId; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatRefundDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatRefundDto.java new file mode 100644 index 000000000..1b4f25a79 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatRefundDto.java @@ -0,0 +1,27 @@ +package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 退款入参 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ThirdMiniWechatRefundDto { + + private Long orderId; + + private String wechantOrderId; + + private Long refundId; + + private Integer orderPrice; + + private Integer refundPrice; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatRefundQueryDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatRefundQueryDto.java new file mode 100644 index 000000000..67f3d6de7 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/oathmini/pay/wechat/ThirdMiniWechatRefundQueryDto.java @@ -0,0 +1,16 @@ +package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat; + +import lombok.Data; + +/** + * 微信退款查询入参 + */ +@Data +public class ThirdMiniWechatRefundQueryDto { + + /** + * 退款id + */ + private String refundId; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/ThirdMinAppOAth2LoginVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/ThirdMinAppOAth2LoginVo.java index 656957d6a..f244ed88a 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/ThirdMinAppOAth2LoginVo.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/ThirdMinAppOAth2LoginVo.java @@ -9,4 +9,6 @@ public class ThirdMinAppOAth2LoginVo { private String refreshToken; + private String errorCode; + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantRefunCallbackSoureVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantRefunCallbackSoureVo.java new file mode 100644 index 000000000..e413ce7f5 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantRefunCallbackSoureVo.java @@ -0,0 +1,30 @@ +package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat; + +import lombok.Data; + +/** + * 微信退款回调加密的返回参数 + */ +@Data +public class ThirdMiniWechantRefunCallbackSoureVo { + + /** + * 公众账号ID + */ + private String appid; + + /** + * 退款的商户号 + */ + private String mch_id; + + /** + * 随机字符串 + */ + private String nonce_str; + + /** + * 加密信息 + */ + private String req_info; +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantRefunCallbackVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantRefunCallbackVo.java new file mode 100644 index 000000000..c935228b1 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantRefunCallbackVo.java @@ -0,0 +1,77 @@ +package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 微信退款回调返回参数 + */ +@Data +public class ThirdMiniWechantRefunCallbackVo { + + 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-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantReverseVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantReverseVo.java new file mode 100644 index 000000000..a6af3edbc --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechantReverseVo.java @@ -0,0 +1,44 @@ +package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 撤销订单返回 + */ +@Data +public class ThirdMiniWechantReverseVo { + 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(ThirdMiniWechantReverseVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(ThirdMiniWechantReverseVo.SUCCESS, result_code); + } + + public boolean isAllSuccess() { + return isHttpSucess() && isPaySucess(); + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatQueryVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatQueryVo.java new file mode 100644 index 000000000..c444c19b7 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatQueryVo.java @@ -0,0 +1,125 @@ +package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 查询订单返回 + */ +@Data +public class ThirdMiniWechatQueryVo { + 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(ThirdMiniWechatQueryVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(ThirdMiniWechatQueryVo.SUCCESS, result_code); + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatRefundQueryVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatRefundQueryVo.java new file mode 100644 index 000000000..4b335d07b --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatRefundQueryVo.java @@ -0,0 +1,102 @@ +package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 退款返回 + */ +@Data +public class ThirdMiniWechatRefundQueryVo { + + 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(ThirdMiniWechatRefundQueryVo.SUCCESS, err_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(ThirdMiniWechatRefundQueryVo.SUCCESS, result_code); + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatRefundVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatRefundVo.java new file mode 100644 index 000000000..897514e75 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/oathmini/pay/wechat/ThirdMiniWechatRefundVo.java @@ -0,0 +1,84 @@ +package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 退款返回 + */ +@Data +public class ThirdMiniWechatRefundVo { + + 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(ThirdMiniWechatRefundVo.SUCCESS, return_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(ThirdMiniWechatRefundVo.SUCCESS, result_code); + } + + public boolean isAllSuccess() { + return isHttpSucess() && isPaySucess(); + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/MiniAppConfig.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/MiniAppConfig.java index df5a0318d..ca47b038b 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/MiniAppConfig.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/MiniAppConfig.java @@ -21,10 +21,46 @@ public class MiniAppConfig { @Data public static class WechatConfig { + /** + * 微信公共平台 appId + */ private String appId; + /** + * 微信公共平台 appSecret + */ private String appSecret; + /** + * 商户号 + */ + private String merchantId; + + /** + * 商户证书序列path + */ + private String merchantSerialPath; + + /** + * 商户APIV2密钥 + */ + private String apiV2Key; + + /** + * 退款回调地址 + */ + private String refundCallbackUrl; + + /** + * 调用ip + */ + private String spbillCreateIp; + + /** + * 微信支付接口地址 + */ + private String baseUrl; + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/oathmini/ThirdMinAppOAth2Cotroller.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/oathmini/ThirdMinAppOAth2Cotroller.java index 59123ca2c..3c062ab13 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/oathmini/ThirdMinAppOAth2Cotroller.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/oathmini/ThirdMinAppOAth2Cotroller.java @@ -1,7 +1,9 @@ package com.bsd.pjcloud.thirdparty.controller.oathmini; import com.bsd.pjcloud.common.core.util.R; -import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto; +import com.bsd.pjcloud.common.security.annotation.Inner; +import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto; import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppService; import com.bsd.pjcloud.thirdparty.vo.oathmini.ThirdMinAppOAth2LoginVo; import io.swagger.v3.oas.annotations.Operation; @@ -20,11 +22,18 @@ public class ThirdMinAppOAth2Cotroller { private final ThirdMiniAppService thirdMiniAppService; - @Operation(summary = "微信小程序登录") + @Operation(summary = "小程序登录") @PostMapping("/auto-admin-login") - public R wechatLogin(@RequestBody ThirdMinAppOAth2LoginDto dto) { + @Inner(value = false) + public R autoAdminLogin(@RequestBody ThirdMiniAppOAth2LoginDto dto) { return R.ok(thirdMiniAppService.adminLogin(dto)); } + @Operation(summary = "小程序获取用户唯一编码") + @PostMapping("/get-unique") + @Inner(value = false) + public R getUniqueCode(@RequestBody ThirdMiniAppGetUniqueDto dto) { + return R.ok(thirdMiniAppService.getUniqueCode(dto)); + } } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppService.java index 9f3278e1f..243b90df7 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppService.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppService.java @@ -1,11 +1,19 @@ package com.bsd.pjcloud.thirdparty.service; - -import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto; import com.bsd.pjcloud.thirdparty.vo.oathmini.ThirdMinAppOAth2LoginVo; public interface ThirdMiniAppService { - ThirdMinAppOAth2LoginVo adminLogin(ThirdMinAppOAth2LoginDto dto); + /** + * 小程序登录 + */ + ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto); + + /** + * 小程序获取用户唯一编码 + */ + String getUniqueCode(ThirdMiniAppGetUniqueDto dto); } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppWechatService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppWechatService.java index 01fc02278..3071ab31a 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppWechatService.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMiniAppWechatService.java @@ -2,6 +2,18 @@ package com.bsd.pjcloud.thirdparty.service; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechantReverseDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatQueryDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundQueryDto; +import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechantReverseVo; +import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatQueryVo; +import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatRefundQueryVo; +import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatRefundVo; +import org.springframework.http.HttpEntity; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.util.Map; public interface ThirdMiniAppWechatService { @@ -15,4 +27,29 @@ public interface ThirdMiniAppWechatService { */ WxMaPhoneNumberInfo getPhone(String code); + /** + * 查询订单 + */ + ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto); + + /** + * 撤销订单 + */ + ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto); + + /** + * 申请退款 + */ + ThirdMiniWechatRefundVo refund(ThirdMiniWechatRefundDto dto); + + /** + * 查询退款 + */ + ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto); + + /** + * 退款回调 + */ + String refundCallback(HttpEntity httpEntity, @RequestHeader Map headers); + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppServiceImpl.java index a862cec46..35886dfcc 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppServiceImpl.java @@ -6,10 +6,14 @@ import com.bsd.pjcloud.admin.api.dto.UserInfo; import com.bsd.pjcloud.admin.api.dto.UserTokenDTO; import com.bsd.pjcloud.admin.api.feign.RemoteTokenService; import com.bsd.pjcloud.admin.api.feign.RemoteUserService; -import com.bsd.pjcloud.common.core.util.R; +import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum; +import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto; +import com.bsd.pjcloud.app.api.dto.AppUserInfo; +import com.bsd.pjcloud.app.api.feign.RemoteAppUserService; import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformLoginErrorEnum; import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum; -import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto; import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppAliPayService; import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppService; import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppWechatService; @@ -19,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import javax.net.ssl.*; import java.util.Map; /** @@ -35,28 +40,53 @@ public class ThirdMiniAppServiceImpl implements ThirdMiniAppService { private final RemoteUserService remoteUserService; private final RemoteTokenService remoteTokenService; + private final RemoteAppUserService remoteAppUserService; + /** + * 小程序登录 + */ @Override - public ThirdMinAppOAth2LoginVo adminLogin(ThirdMinAppOAth2LoginDto dto) { + public ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto) { ThirdMinAppOAth2LoginVo vo = new ThirdMinAppOAth2LoginVo(); // 微信小程序 - if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECAHT.getType())) { + if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) { // 获取手机号 - WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getCode()); + WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getPhoneCode()); if (ObjectUtil.isEmpty(phoneInfo)) { - throw new RuntimeException(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType()); + vo.setErrorCode(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType()); + return vo; } // 根据手机号查询用户 UserInfo userInfo = remoteUserService.getInnerByPhone(phoneInfo.getPurePhoneNumber()).getData(); if (ObjectUtil.isEmpty(userInfo)) { - throw new RuntimeException(MiniPlatformLoginErrorEnum.USER_NOT_EXIST.getType()); + vo.setErrorCode(MiniPlatformLoginErrorEnum.USER_NOT_EXIST.getType()); + return vo; + } + // 获取用户唯一编号 + ThirdMiniAppGetUniqueDto getUniqueDto = new ThirdMiniAppGetUniqueDto(); + getUniqueDto.setMiniPlatformType(MiniPlatformTypeEnum.WECHAT); + getUniqueDto.setCode(dto.getPhoneCode()); + getUniqueDto.setUserId(userInfo.getSysUser().getUserId()); + String uniqueCode = getUniqueCode(getUniqueDto); + // 同步到社交用户 + AppAdminSyncDto appAdminSyncDto = new AppAdminSyncDto(); + appAdminSyncDto.setUniqueCode(uniqueCode); + appAdminSyncDto.setUserTypeEnum(AppUserTypeEnum.MINI_WECHAT); + appAdminSyncDto.setAdminUserId(userInfo.getSysUser().getUserId()); + appAdminSyncDto.setUsername(userInfo.getSysUser().getUsername()); + appAdminSyncDto.setAvatarImage(userInfo.getSysUser().getAvatar()); + AppUserInfo appUserInfo = remoteAppUserService.syncAdminAccountInfo(appAdminSyncDto).getData(); + if (ObjectUtil.isEmpty(appUserInfo)) { + vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType()); + return vo; } // 执行登录 UserTokenDTO userTokenDTO = new UserTokenDTO(); userTokenDTO.setSysUser(userInfo.getSysUser()); Map dataMap = (Map) remoteTokenService.generateToken(userTokenDTO).getData(); if (ObjectUtil.isEmpty(dataMap)) { - throw new RuntimeException(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType()); + vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType()); + return vo; } vo.setAccessToken(String.valueOf(dataMap.getOrDefault("accessToken", ""))); vo.setRefreshToken(String.valueOf(dataMap.getOrDefault("refreshToken", ""))); @@ -68,4 +98,18 @@ public class ThirdMiniAppServiceImpl implements ThirdMiniAppService { return vo; } + /** + * 小程序获取用户唯一编码 + */ + @Override + public String getUniqueCode(ThirdMiniAppGetUniqueDto dto) { + String uniqueCode = null; + if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) { + uniqueCode = thirdMiniAppWechatService.getOpenId(dto.getCode()); + } else if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.ALI_PAY.getType())) { + + } + return uniqueCode; + } + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppWechatServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppWechatServiceImpl.java index bbac53c5d..bd5d9b196 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppWechatServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/miniapp/ThirdMiniAppWechatServiceImpl.java @@ -3,14 +3,37 @@ package com.bsd.pjcloud.thirdparty.service.impl.miniapp; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.hutool.core.codec.Base64; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.XmlUtil; +import cn.hutool.json.JSONUtil; import com.bsd.pjcloud.thirdparty.config.MiniAppConfig; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechantReverseDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatQueryDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundDto; +import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundQueryDto; import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppWechatService; +import com.bsd.pjcloud.thirdparty.utils.miniapp.pay.wechat.ThirdMiniWechantPayConstant; +import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.http.HttpEntity; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.*; +import java.io.FileInputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + /** * 微信小程序(小程序版本) */ @@ -20,7 +43,7 @@ import org.springframework.validation.annotation.Validated; @RequiredArgsConstructor public class ThirdMiniAppWechatServiceImpl implements ThirdMiniAppWechatService { - private final String TAG = "微信小程序(小程序版本)"; + private final String TAG = "微信小程序支付(小程序版本)"; private final MiniAppConfig miniAppConfig; @@ -62,4 +85,291 @@ public class ThirdMiniAppWechatServiceImpl implements ThirdMiniAppWechatService } } + /** + * 查询订单 + */ + @Override + public ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto) { + MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig(); + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatConfig.getAppId()); + // 商户号 + params.put("mch_id", wechatConfig.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)); + ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.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; + } + ThirdMiniWechatQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatQueryVo.class); + log.debug("|{}|查询订单,json,res|{}", TAG, JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("|{}|查询订单,异常", TAG, e); + return null; + } + } + + /** + * 撤销订单 + */ + @Override + public ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto) { + MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig(); + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatConfig.getAppId()); + // 商户号 + params.put("mch_id", wechatConfig.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)); + ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REVERSE); + api.setSslSocketFactory(createSSLSocketFactory()); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("|{}|撤销订单,json,xml|{}", TAG, res); + if (ObjectUtil.isEmpty(res)) { + log.error("|{}|撤销订单,res为空", TAG); + return null; + } + ThirdMiniWechantReverseVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechantReverseVo.class); + log.debug("|{}|撤销订单,json,res|{}", TAG, JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("|{}|撤销订单,异常", TAG, e); + return null; + } + } + + /** + * 申请退款 + */ + @Override + public ThirdMiniWechatRefundVo refund(ThirdMiniWechatRefundDto dto) { + MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig(); + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatConfig.getAppId()); + // 商户号 + params.put("mch_id", wechatConfig.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", wechatConfig.getRefundCallbackUrl()); + // 生成签名 + params.put("sign", generateSign(params)); + ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REFUND); + api.setSslSocketFactory(createSSLSocketFactory()); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("|{}|申请退款,json,xml|{}", TAG, res); + if (ObjectUtil.isEmpty(res)) { + log.error("|{}|申请退款,res为空", TAG); + return null; + } + ThirdMiniWechatRefundVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundVo.class); + log.debug("|{}|申请退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("|{}|申请退款,异常", TAG, e); + return null; + } + } + + /** + * 查询退款 + */ + @Override + public ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto) { + MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig(); + try { + Map params = new HashMap<>(); + // 公众账号ID + params.put("appid", wechatConfig.getAppId()); + // 商户号 + params.put("mch_id", wechatConfig.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)); + ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REFUND_QUERY); + String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body(); + log.debug("|{}|查询退款,json,xml|{}", TAG, res); + if (ObjectUtil.isEmpty(res)) { + log.error("|{}|查询退款,res为空", TAG); + return null; + } + ThirdMiniWechatRefundQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundQueryVo.class); + log.debug("|{}|查询退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + return vo; + } catch (Exception e) { + log.error("|{}|查询退款,异常", TAG, e); + return null; + } + } + + /** + * 退款回调 + */ + @Override + public String refundCallback(HttpEntity httpEntity, Map headers) { + String body = httpEntity.getBody(); + ThirdMiniWechantRefunCallbackVo decrypt = decrypt(body); + if (ObjectUtil.isEmpty(decrypt)) { + // 告诉微信错误 + return ThirdMiniWechantRefunCallbackVo.wechantError(); + } + boolean isSuccess = true; + return isSuccess ? ThirdMiniWechantRefunCallbackVo.wechantSuccess() : ThirdMiniWechantRefunCallbackVo.wechantError(); + } + + /** + * 解密回调信息解密 + */ + private ThirdMiniWechantRefunCallbackVo decrypt(String xml) { + MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig(); + try { + ThirdMiniWechantRefunCallbackSoureVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(xml)), ThirdMiniWechantRefunCallbackSoureVo.class); + String reqInfo = vo.getReq_info(); + // 1 对加密串A做base64解码,得到加密串B + byte[] encryptedBytes = Base64.decode(reqInfo); + // 2 对商户key做md5,得到32位小写key + String md5Key = DigestUtils.md5Hex(wechatConfig.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); + ThirdMiniWechantRefunCallbackVo entity = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(json)), ThirdMiniWechantRefunCallbackVo.class); + log.debug("|{}|解密回调信息,json|{}", TAG, JSONUtil.toJsonStr(entity)); + return entity; + } catch (Exception e) { + e.printStackTrace(); + log.error("|{}|解密回调信息解密异常", TAG, e); + return null; + } + } + + /** + * 生成微信支付签名 + */ + public String generateSign(Map params) { + String apiKey = miniAppConfig.getWechatConfig().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("|{}|微信支付签名生成失败", TAG, e); + } + return ""; + } + + private ThirdMiniWechantPayConstant.Api initApi(ThirdMiniWechantPayConstant.Api api) { + api.setBaseUrl(miniAppConfig.getWechatConfig().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(miniAppConfig.getWechatConfig().getMerchantSerialPath()); + keyStore.load(certStream, miniAppConfig.getWechatConfig().getMerchantId().toCharArray()); + certStream.close(); + // 创建KeyManagerFactory + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, miniAppConfig.getWechatConfig().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(); + } + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/miniapp/pay/wechat/ThirdMiniWechantPayConstant.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/miniapp/pay/wechat/ThirdMiniWechantPayConstant.java new file mode 100644 index 000000000..4ea7da380 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/miniapp/pay/wechat/ThirdMiniWechantPayConstant.java @@ -0,0 +1,67 @@ +package com.bsd.pjcloud.thirdparty.utils.miniapp.pay.wechat; + +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 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ThirdMiniWechantPayConstant { + + 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-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml index 234ce7451..12bb2ca8c 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml @@ -179,5 +179,11 @@ mini-platform: wechat-config: app-id: wx11771c7bf2913cb2 app-secret: a6b0d036b229117595687a7c1705d332 + merchant-id: 1106210589 + api-v2-key: qr0w9WkAu6GG3uuxPjDT7bcdIVoBr0rw + merchant-serial-path: /Users/dengzhangchen/Desktop/backups/pay/cert/apiclient_cert.p12 + refund-callback-url: https://rj4jv5rwqs.by.takin.cc/hard/hard-wechant-pay/callback/refund + spbill-create-ip: 59.202.170.152 + base-url: https://api.mch.weixin.qq.com ali-pay-config: app-id: