diff --git a/db/1000pjcloudx_thirdparty.sql b/db/1000pjcloudx_thirdparty.sql index c5e42e9eb..488f0cc4d 100644 --- a/db/1000pjcloudx_thirdparty.sql +++ b/db/1000pjcloudx_thirdparty.sql @@ -135,3 +135,41 @@ CREATE TABLE `third_zy_id_dict` DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC COMMENT ='正元字典id对应 id + bizType 唯一'; + +-- ---------------------------- +-- Table structure for third_pay_order +-- ---------------------------- +DROP TABLE IF EXISTS `third_pay_order`; +CREATE TABLE `third_pay_order` +( + `id` bigint NOT NULL COMMENT '主键', + + `pay_platform_type` varchar(32) NOT NULL COMMENT '支付平台类型', + `biz_type` varchar(32) NOT NULL COMMENT '支付类型', + `biz_id` varchar(128) NOT NULL COMMENT '支付相关id', + `user_id` bigint NOT NULL COMMENT '用户id', + `user_code` varchar(64) DEFAULT NULL COMMENT '用户code', + `price` int NOT NULL COMMENT '支付金额(分)', + `status` varchar(128) DEFAULT NULL COMMENT '支付状态', + + `pay_no` varchar(128) DEFAULT NULL COMMENT '支付订单号', + `pay_time` datetime DEFAULT NULL COMMENT '支付时间', + `pay_res` text DEFAULT NULL COMMENT '支付返回', + + `refund_no` varchar(128) DEFAULT NULL COMMENT '退款订单号', + `refund_time` datetime DEFAULT NULL COMMENT '退款时间', + `refund_res` text DEFAULT NULL COMMENT '退款返回', + + `expire_time` datetime DEFAULT NULL COMMENT '订单过期时间', + + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + `update_by` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '删除时间', + `tenant_id` bigint(20) DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci + ROW_FORMAT = DYNAMIC COMMENT ='第三方支付订单'; \ No newline at end of file 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..c57fe569d 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,11 @@ public interface RemoteAppUserService { @GetMapping("/appsocial/info/{inStr}") R social(@PathVariable("inStr") String inStr); + /** + * 同步admin账户信息为app账户 + */ + @NoToken + @PostMapping("/appsocial/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..abbbbd0ba 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账户 + */ + @Inner(value = true) + @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..be977c7d8 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); + /** + * 同步admin账户信息为app账户 + */ + AppUserInfo syncAdminAccountInfo(AppAdminSyncDto dto); - /** - * 根据入参查询用户信息 - * @param inStr - * @return - */ - AppUserInfo getUserInfo(String inStr); + /** + * 绑定社交账号 + */ + 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..9afb7fd58 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; @@ -35,52 +40,67 @@ import org.springframework.stereotype.Service; import java.util.Map; -/** - * @author pjcloud - * @date 2018年08月16日 - */ + @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; - } - /** - * 根据入参查询用户信息 - * @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 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(appUser); + } + + /** + * 绑定社交账号 + */ + @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/MiniPlatformLoginErrorEnum.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformLoginErrorEnum.java new file mode 100644 index 000000000..9318e5426 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformLoginErrorEnum.java @@ -0,0 +1,29 @@ +package com.bsd.pjcloud.thirdparty.constant.miniplatform; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 小程序平台登录错误 + */ +@AllArgsConstructor +@Getter +public enum MiniPlatformLoginErrorEnum { + + GET_PHONE_ERROR("10", "获取手机号错误"), + USER_NOT_EXIST("20", "用户不存在"), + LOGIN_ERROR("30", "登录错误"), + ; + + private final String type; + private final String description; + + public static MiniPlatformLoginErrorEnum valueOfByType(String type) { + if (ObjectUtil.isEmpty(type)) return null; + return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get(); + } + +} 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 new file mode 100644 index 000000000..df9b4c697 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/miniplatform/MiniPlatformTypeEnum.java @@ -0,0 +1,29 @@ +package com.bsd.pjcloud.thirdparty.constant.miniplatform; + +import cn.hutool.core.util.ObjectUtil; +import com.bsd.pjcloud.thirdparty.constant.ThirdKeyTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 小程序平台 + */ +@AllArgsConstructor +@Getter +public enum MiniPlatformTypeEnum { + + WECHAT("10", "微信小程序"), + ALI_PAY("20", "支付宝"), + ; + + private final String type; + private final String description; + + public static MiniPlatformTypeEnum valueOfByType(String type) { + if (ObjectUtil.isEmpty(type)) return null; + return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get(); + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/pay/ThirdPayOrderBizTypeEnum.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/pay/ThirdPayOrderBizTypeEnum.java new file mode 100644 index 000000000..3e53514a8 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/pay/ThirdPayOrderBizTypeEnum.java @@ -0,0 +1,27 @@ +package com.bsd.pjcloud.thirdparty.constant.pay; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 第三方支付业务类型 + */ +@AllArgsConstructor +@Getter +public enum ThirdPayOrderBizTypeEnum { + + MINI_APP_WALLET_RECHARGE("10", "小程序用户钱包充值"), + ; + + private final String type; + private final String description; + + public static ThirdPayOrderBizTypeEnum valueOfByType(String type) { + if (ObjectUtil.isEmpty(type)) return null; + return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get(); + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/pay/ThirdPayOrderStatusEnum.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/pay/ThirdPayOrderStatusEnum.java new file mode 100644 index 000000000..85edf5fde --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/pay/ThirdPayOrderStatusEnum.java @@ -0,0 +1,32 @@ +package com.bsd.pjcloud.thirdparty.constant.pay; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 第三方支付订单状态 + */ +@AllArgsConstructor +@Getter +public enum ThirdPayOrderStatusEnum { + PAY_UNPAID("10", "未支付"), + PAY_SUCCESS("20", "支付成功"), + PAY_FAILED("30", "已经支付"), + + REFUNDING("100", "退款中"), + REFUND_SUCCESS("200", "退款成功"), + REFUND_FAILED("300", "退款失败"), + ; + + private final String type; + private final String description; + + public static ThirdPayOrderStatusEnum valueOfByType(String type) { + if (ObjectUtil.isEmpty(type)) return null; + return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get(); + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppGetUniqueDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppGetUniqueDto.java new file mode 100644 index 000000000..c6e30d9fe --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppGetUniqueDto.java @@ -0,0 +1,25 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus; + +import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class ThirdMiniAppGetUniqueDto { + + /** + * 小程序平台 + */ + @NotNull(message = "小程序平台标识不能为空") + private MiniPlatformTypeEnum miniPlatformType; + + @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/appplus/ThirdMiniAppOAth2LoginDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppOAth2LoginDto.java new file mode 100644 index 000000000..425b9ea9f --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppOAth2LoginDto.java @@ -0,0 +1,23 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus; + +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/appplus/ThirdMiniAppPayDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppPayDto.java new file mode 100644 index 000000000..97d375cbd --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/ThirdMiniAppPayDto.java @@ -0,0 +1,42 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus; + +import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum; +import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderBizTypeEnum; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class ThirdMiniAppPayDto { + + /** + * 充值业务类型 + */ + @NotNull(message = "充值业务类型不能为空") + private ThirdPayOrderBizTypeEnum bizType; + + /** + * 充值业务id + */ + @NotEmpty(message = "充值业务id不能为空") + private String bizId; + + + /** + * 小程序平台 + */ + @NotNull(message = "小程序平台标识不能为空") + private MiniPlatformTypeEnum miniPlatformType; + + /** + * 金额(分) + */ + private Integer amount; + + /** + * 用户标识 + */ + @NotEmpty(message = "用户标识不能为空") + private String openId; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniJsapiPayDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniJsapiPayDto.java new file mode 100644 index 000000000..b60e24276 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniJsapiPayDto.java @@ -0,0 +1,42 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat; + +import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderBizTypeEnum; +import lombok.Data; + +/** + * JSAPI/小程序下单 + */ +@Data +public class ThirdMiniJsapiPayDto { + + /** + * 充值业务类型 + */ + private ThirdPayOrderBizTypeEnum bizType; + + /** + * 充值业务id + */ + private String bizId; + + /** + * 商户订单号 + */ + private String outTradeNo; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户标识 + */ + private String openid; + + /** + * 金额(分) + */ + private Integer amount; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechantReverseDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechantReverseDto.java new file mode 100644 index 000000000..8aa89f5b8 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechantReverseDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus.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/appplus/pay/wechat/ThirdMiniWechatQueryDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatQueryDto.java new file mode 100644 index 000000000..09e2a11cc --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatQueryDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus.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/appplus/pay/wechat/ThirdMiniWechatRefundDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatRefundDto.java new file mode 100644 index 000000000..1a8c17856 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatRefundDto.java @@ -0,0 +1,26 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat; + +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 退款入参 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ThirdMiniWechatRefundDto { + + @NotEmpty + private String payNo; + + /** + * 为null就全额退款 + */ + private Integer refundPrice; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatRefundQueryDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatRefundQueryDto.java new file mode 100644 index 000000000..ac69ea0fa --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdMiniWechatRefundQueryDto.java @@ -0,0 +1,16 @@ +package com.bsd.pjcloud.thirdparty.dto.appplus.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/dto/pay/ThirdPayOrderDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/pay/ThirdPayOrderDto.java new file mode 100644 index 000000000..f0961ce38 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/pay/ThirdPayOrderDto.java @@ -0,0 +1,15 @@ +package com.bsd.pjcloud.thirdparty.dto.pay; + +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ThirdPayOrderDto extends ThirdPayOrderEntity { + + private LocalDateTime[] payTimeList; + + private LocalDateTime[] refundTimeList; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/entity/pay/ThirdPayOrderEntity.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/entity/pay/ThirdPayOrderEntity.java new file mode 100755 index 000000000..138eb5b4c --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/entity/pay/ThirdPayOrderEntity.java @@ -0,0 +1,179 @@ +package com.bsd.pjcloud.thirdparty.entity.pay; + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import com.bsd.pjcloud.common.core.util.TenantTable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 第三方支付订单 + */ +@Data +@TenantTable +@TableName("third_pay_order") +@EqualsAndHashCode(callSuper = true) +@Schema(description = "第三方支付订单") +public class ThirdPayOrderEntity extends Model { + + + /** + * 主键 + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "主键") + private Long id; + + /** + * 支付平台类型 + */ + @Schema(description = "支付平台类型") + private String payPlatformType; + + /** + * 支付类型 + */ + @Schema(description = "支付类型") + private String bizType; + + /** + * 支付相关id + */ + @Schema(description = "支付相关id") + private String bizId; + + /** + * 用户id + */ + @Schema(description = "用户id") + private Long userId; + + /** + * 用户code + */ + @Schema(description = "用户code") + private String userCode; + + /** + * 支付金额(分) + */ + @Schema(description = "支付金额(分)") + private Integer price; + + /** + * 支付状态 + */ + @Schema(description = "支付状态") + private String status; + + /** + * 支付订单号 + */ + @Schema(description = "支付订单号") + private String payNo; + + /** + * 支付时间 + */ + @Schema(description = "支付时间") + private LocalDateTime payTime; + + /** + * 支付参数 + */ + @Schema(description = "支付参数") + private String payRep; + + /** + * 支付回调返回 + */ + @Schema(description = "支付回调返回") + private String payCallbackRes; + + /** + * 支付返回 + */ + @Schema(description = "支付返回") + private String payRes; + + /** + * 退款订单号 + */ + @Schema(description = "退款订单号") + private String refundNo; + + /** + * 退款回调返回 + */ + @Schema(description = "退款回调返回") + private String refundCallbackRes; + + /** + * 退款时间 + */ + @Schema(description = "退款时间") + private LocalDateTime refundTime; + + /** + * 退款参数 + */ + @Schema(description = "退款参数") + private String refundRep; + + /** + * 退款返回 + */ + @Schema(description = "退款返回") + private String refundRes; + + /** + * 订单过期时间 + */ + @Schema(description = "订单过期时间") + private LocalDateTime expireTime; + + /** + * 创建人 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description = "创建人") + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description = "创建时间") + private LocalDateTime createTime; + + /** + * 更新人 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + @Schema(description = "更新人") + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + @Schema(description = "删除时间") + private String delFlag; + + /** + * tenantId + */ + @Schema(description = "tenantId") + private Long tenantId; +} \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/ThirdMinAppOAth2LoginVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/ThirdMinAppOAth2LoginVo.java new file mode 100644 index 000000000..e1e4fa5c5 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/ThirdMinAppOAth2LoginVo.java @@ -0,0 +1,14 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus; + +import lombok.Data; + +@Data +public class ThirdMinAppOAth2LoginVo { + + private Object accessToken; + + private Object refreshToken; + + private String errorCode; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/ThirdMiniAppPayVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/ThirdMiniAppPayVo.java new file mode 100644 index 000000000..63e527c76 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/ThirdMiniAppPayVo.java @@ -0,0 +1,12 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.pay; + +import lombok.Data; + +import java.util.HashMap; + +@Data +public class ThirdMiniAppPayVo { + + private HashMap miniAppPayParams; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniJsapiPayVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniJsapiPayVo.java new file mode 100644 index 000000000..1d5b6ddcd --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniJsapiPayVo.java @@ -0,0 +1,52 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.pay.wechat; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +import java.util.HashMap; + +/** + * JSAPI/小程序下单 + */ +@Data +public class ThirdMiniJsapiPayVo { + + 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; + + private String trade_type; + + private String prepay_id; + + private String code_url; + + private HashMap miniAppPayParams; + + 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/appplus/pay/wechat/ThirdMiniWechantRefunCallbackSoureVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechantRefunCallbackSoureVo.java new file mode 100644 index 000000000..6c1855089 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechantRefunCallbackSoureVo.java @@ -0,0 +1,30 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.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/appplus/pay/wechat/ThirdMiniWechantRefunCallbackVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechantRefunCallbackVo.java new file mode 100644 index 000000000..e5a4657be --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechantRefunCallbackVo.java @@ -0,0 +1,77 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.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/appplus/pay/wechat/ThirdMiniWechantReverseVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechantReverseVo.java new file mode 100644 index 000000000..d4b20ce4b --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechantReverseVo.java @@ -0,0 +1,44 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.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/appplus/pay/wechat/ThirdMiniWechatQueryVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechatQueryVo.java new file mode 100644 index 000000000..91ecf8812 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechatQueryVo.java @@ -0,0 +1,140 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.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); + } + + 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/appplus/pay/wechat/ThirdMiniWechatRefundQueryVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechatRefundQueryVo.java new file mode 100644 index 000000000..fc1917b0f --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechatRefundQueryVo.java @@ -0,0 +1,116 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.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) || ObjectUtil.isEmpty(err_code); + } + + public boolean isPaySucess() { + return ObjectUtil.equals(ThirdMiniWechatRefundQueryVo.SUCCESS, result_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/appplus/pay/wechat/ThirdMiniWechatRefundVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechatRefundVo.java new file mode 100644 index 000000000..a4c522b16 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/appplus/pay/wechat/ThirdMiniWechatRefundVo.java @@ -0,0 +1,84 @@ +package com.bsd.pjcloud.thirdparty.vo.appplus.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-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/pay/ThirdPayOrderVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/pay/ThirdPayOrderVo.java new file mode 100644 index 000000000..4051fe63c --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/pay/ThirdPayOrderVo.java @@ -0,0 +1,13 @@ +package com.bsd.pjcloud.thirdparty.vo.pay; + +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import lombok.Data; + +@Data +public class ThirdPayOrderVo extends ThirdPayOrderEntity { + + private String username; + + private String userPhone; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml index 40b4575d6..2c215cfc2 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml @@ -13,13 +13,24 @@ pjcloud-thirdparty-biz - + com.aliyun aliyun-java-sdk-core 4.5.0 - + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + + + + com.github.binarywang + wx-java-miniapp-spring-boot-starter + 4.7.0 + com.hikvision.ga artemis-http-client diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/AppPlusPayConfig.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/AppPlusPayConfig.java new file mode 100644 index 000000000..1f7da63e4 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/AppPlusPayConfig.java @@ -0,0 +1,79 @@ +package com.bsd.pjcloud.thirdparty.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 小程序平台配置 + */ +@Component +@ConfigurationProperties(prefix = "app-plus.pay") +@Data +public class AppPlusPayConfig { + + + private WechatConfig wechatConfig; + + private AliPayConfig aliPayConfig; + + + @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 payCallbackUrl; + + /** + * 退款回调地址 + */ + private String refundCallbackUrl; + + /** + * 调用ip + */ + private String spbillCreateIp; + + /** + * 微信支付接口地址 + */ + private String baseUrl; + + } + + + @Data + public static class AliPayConfig { + + private String appId; + + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/initconfig/WechatConfiguration.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/initconfig/WechatConfiguration.java new file mode 100644 index 000000000..20c3b7520 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/initconfig/WechatConfiguration.java @@ -0,0 +1,39 @@ +package com.bsd.pjcloud.thirdparty.config.initconfig; + + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import com.bsd.pjcloud.thirdparty.config.AppPlusPayConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Slf4j +@Configuration +public class WechatConfiguration { + + private final AppPlusPayConfig properties; + + @Autowired + public WechatConfiguration(AppPlusPayConfig properties) { + this.properties = properties; + } + + + @Bean + public WxMaService wxMaService() { + AppPlusPayConfig.WechatConfig wechatConfig = properties.getWechatConfig(); + + WxMaDefaultConfigImpl wxMaDefaultConfig = new WxMaDefaultConfigImpl(); + wxMaDefaultConfig.setAppid(wechatConfig.getAppId()); + wxMaDefaultConfig.setSecret(wechatConfig.getAppSecret()); + wxMaDefaultConfig.setMsgDataFormat("JSON"); + + WxMaService maService = new WxMaServiceImpl(); + maService.setWxMaConfig(wxMaDefaultConfig); + return maService; + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/appplus/ThirdMinAppPayCotroller.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/appplus/ThirdMinAppPayCotroller.java new file mode 100644 index 000000000..be10d640e --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/appplus/ThirdMinAppPayCotroller.java @@ -0,0 +1,66 @@ +package com.bsd.pjcloud.thirdparty.controller.appplus; + +import com.bsd.pjcloud.common.core.util.R; +import com.bsd.pjcloud.common.security.annotation.Inner; +import com.bsd.pjcloud.common.security.service.PjcloudUser; +import com.bsd.pjcloud.common.security.util.SecurityUtils; +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppPayDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat.ThirdMiniWechatRefundDto; +import com.bsd.pjcloud.thirdparty.service.ThirdAppPlusService; +import com.bsd.pjcloud.thirdparty.vo.appplus.pay.ThirdMiniAppPayVo; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +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.*; + +import java.util.Map; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/third-app-pay") +@Tag(description = "third-app-pay", name = "小程序支付") +@SecurityRequirement(name = HttpHeaders.AUTHORIZATION) +public class ThirdMinAppPayCotroller { + + private final ThirdAppPlusService thirdMiniAppService; + + + @Operation(summary = "小程序支付退款") + @PostMapping("/refund") + public R miniRefund(@Valid @RequestBody ThirdMiniWechatRefundDto dto) { + return R.ok(thirdMiniAppService.miniRefund(dto)); + } + + /* ************************************* start app start ************************************* */ + + @Operation(summary = "小程序支付") + @PostMapping("/app/pay") + public R miniPay(@Validated @RequestBody ThirdMiniAppPayDto dto) { + PjcloudUser user = SecurityUtils.getUser(); + return R.ok(thirdMiniAppService.miniPay(user.getId(), dto)); + } + + @Operation(summary = "小程序支付回调") + @PostMapping("/app/pay-callback") + @Inner(value = false) + public R miniPayCallback(HttpEntity httpEntity, @RequestHeader Map headers) { + String body = httpEntity.getBody(); + return R.ok(thirdMiniAppService.miniPayCallback(body, headers)); + } + + @Operation(summary = "小程序退款回调") + @PostMapping("/app/refund-callback") + @Inner(value = false) + public R miniRefundCallback(HttpEntity httpEntity, @RequestHeader Map headers) { + String body = httpEntity.getBody(); + return R.ok(thirdMiniAppService.miniRefundCallback(body, headers)); + } + + /* ************************************* end app end ************************************* */ + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/pay/ThirdPayOrderController.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/pay/ThirdPayOrderController.java new file mode 100755 index 000000000..388988b51 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/pay/ThirdPayOrderController.java @@ -0,0 +1,100 @@ +package com.bsd.pjcloud.thirdparty.controller.pay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.bsd.pjcloud.common.core.util.R; +import com.bsd.pjcloud.common.excel.annotation.ResponseExcel; +import com.bsd.pjcloud.common.log.annotation.SysLog; +import com.bsd.pjcloud.thirdparty.dto.pay.ThirdPayOrderDto; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.service.ThirdPayOrderService; +import com.bsd.pjcloud.thirdparty.vo.pay.ThirdPayOrderVo; +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.springdoc.core.annotations.ParameterObject; +import org.springframework.http.HttpHeaders; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 第三方支付订单 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/third-pay-order") +@Tag(description = "third-pay-order", name = "第三方支付订单管理") +@SecurityRequirement(name = HttpHeaders.AUTHORIZATION) +public class ThirdPayOrderController { + + private final ThirdPayOrderService thirdPayOrderService; + + /** + * 分页查询 + */ + @Operation(summary = "分页查询", description = "分页查询") + @GetMapping("/page") + @PreAuthorize("@pms.hasPermission('third_thirdPayOrder_view')") + public R> getThirdPayOrderPage(@ParameterObject Page page, @ParameterObject ThirdPayOrderDto dto) { + return R.ok(thirdPayOrderService.scopePage(page, dto, null)); + } + + /** + * 通过id查询第三方支付订单 + */ + @Operation(summary = "通过id查询", description = "通过id查询") + @GetMapping("/{id}") + @PreAuthorize("@pms.hasPermission('third_thirdPayOrder_view')") + public R getById(@PathVariable("id") Long id) { + return R.ok(thirdPayOrderService.getById(id)); + } + + /** + * 新增第三方支付订单 + */ + @Operation(summary = "新增第三方支付订单", description = "新增第三方支付订单") + @SysLog("新增第三方支付订单") + @PostMapping + @PreAuthorize("@pms.hasPermission('third_thirdPayOrder_add')") + public R save(@RequestBody ThirdPayOrderEntity thirdPayOrder) { + return R.ok(thirdPayOrderService.save(thirdPayOrder)); + } + + /** + * 修改第三方支付订单 + */ + @Operation(summary = "修改第三方支付订单", description = "修改第三方支付订单") + @SysLog("修改第三方支付订单") + @PutMapping + @PreAuthorize("@pms.hasPermission('third_thirdPayOrder_edit')") + public R updateById(@RequestBody ThirdPayOrderEntity thirdPayOrder) { + return R.ok(thirdPayOrderService.updateById(thirdPayOrder)); + } + + /** + * 通过id删除第三方支付订单 + */ + @Operation(summary = "通过id删除第三方支付订单", description = "通过id删除第三方支付订单") + @SysLog("通过id删除第三方支付订单") + @DeleteMapping + @PreAuthorize("@pms.hasPermission('third_thirdPayOrder_del')") + public R removeById(@RequestBody Long[] ids) { + return R.ok(thirdPayOrderService.removeBatchByIds(CollUtil.toList(ids))); + } + + /** + * 导出excel 表格 + */ + @ResponseExcel + @GetMapping("/export") + @PreAuthorize("@pms.hasPermission('third_thirdPayOrder_export')") + public List export(ThirdPayOrderEntity thirdPayOrder, Long[] ids) { + return thirdPayOrderService.list(Wrappers.lambdaQuery(thirdPayOrder).in(ArrayUtil.isNotEmpty(ids), ThirdPayOrderEntity::getId, ids)); + } + +} \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/mapper/pay/ThirdPayOrderMapper.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/mapper/pay/ThirdPayOrderMapper.java new file mode 100644 index 000000000..ab280c5e4 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/mapper/pay/ThirdPayOrderMapper.java @@ -0,0 +1,17 @@ +package com.bsd.pjcloud.thirdparty.mapper.pay; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.bsd.pjcloud.common.data.datascope.DataScope; +import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper; +import com.bsd.pjcloud.thirdparty.dto.pay.ThirdPayOrderDto; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.vo.pay.ThirdPayOrderVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface ThirdPayOrderMapper extends PjcloudBaseMapper { + + Page scopePage(Page page, @Param("dto") ThirdPayOrderDto dto, DataScope dataScope); + +} \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusAliPayService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusAliPayService.java new file mode 100644 index 000000000..dc2a00212 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusAliPayService.java @@ -0,0 +1,6 @@ +package com.bsd.pjcloud.thirdparty.service; + + +public interface ThirdAppPlusAliPayService { + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusService.java new file mode 100644 index 000000000..f14974351 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusService.java @@ -0,0 +1,44 @@ +package com.bsd.pjcloud.thirdparty.service; + +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppGetUniqueDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppOAth2LoginDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppPayDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat.ThirdMiniWechatRefundDto; +import com.bsd.pjcloud.thirdparty.vo.appplus.ThirdMinAppOAth2LoginVo; +import com.bsd.pjcloud.thirdparty.vo.appplus.pay.ThirdMiniAppPayVo; + +import java.util.Map; + +public interface ThirdAppPlusService { + + /** + * 小程序登录 + */ + ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto); + + /** + * 小程序获取用户唯一编码 + */ + String getUniqueCode(ThirdMiniAppGetUniqueDto dto); + + /** + * 小程序支付 + */ + ThirdMiniAppPayVo miniPay(Long userId, ThirdMiniAppPayDto dto); + + /** + * 小程序退款 + */ + ThirdMiniAppPayVo miniRefund(ThirdMiniWechatRefundDto dto); + + /** + * 小程序支付回调 + */ + String miniPayCallback(String body, Map headers); + + /** + * 小程序退款回调 + */ + String miniRefundCallback(String body, Map headers); + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusWechatService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusWechatService.java new file mode 100644 index 000000000..62d1cc482 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdAppPlusWechatService.java @@ -0,0 +1,59 @@ +package com.bsd.pjcloud.thirdparty.service; + + +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat.*; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.vo.appplus.pay.wechat.*; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.util.Map; + +public interface ThirdAppPlusWechatService { + + /** + * JSAPI/小程序下单 + */ + ThirdMiniJsapiPayVo jsapiPay(ThirdMiniJsapiPayDto dto); + + /** + * 获取openId + */ + String getOpenId(String code); + + /** + * 获取手机号 + */ + WxMaPhoneNumberInfo getPhone(String code); + + /** + * 查询订单 + */ + ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto); + + /** + * 撤销订单 + */ + ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto); + + /** + * 申请退款 + */ + ThirdMiniWechatRefundVo refund(ThirdPayOrderEntity thirdPayOrder, ThirdMiniWechatRefundDto dto); + + /** + * 查询退款 + */ + ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto); + + /** + * 支付的回调通知 + */ + ThirdPayOrderEntity payCallback(String body, @RequestHeader Map headers); + + /** + * 退款回调 + */ + ThirdPayOrderEntity refundCallback(String body, @RequestHeader Map headers); + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPayOrderService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPayOrderService.java new file mode 100755 index 000000000..e3ffc30f2 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPayOrderService.java @@ -0,0 +1,18 @@ +package com.bsd.pjcloud.thirdparty.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.bsd.pjcloud.common.data.datascope.DataScope; +import com.bsd.pjcloud.thirdparty.dto.pay.ThirdPayOrderDto; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.vo.pay.ThirdPayOrderVo; + +public interface ThirdPayOrderService extends IService { + + Page scopePage(Page page, ThirdPayOrderDto dto, DataScope dataScope); + + ThirdPayOrderEntity getByPayNo(String payNo); + + +} \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java new file mode 100644 index 000000000..3351c96cf --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.thirdparty.service.impl.appplus; + +import com.bsd.pjcloud.thirdparty.config.AppPlusPayConfig; +import com.bsd.pjcloud.thirdparty.service.ThirdAppPlusAliPayService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 支付宝小程序(小程序版本) + */ +@Service +@Validated +@Slf4j +@RequiredArgsConstructor +public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService { + + private final AppPlusPayConfig miniAppConfig; + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusServiceImpl.java new file mode 100644 index 000000000..9bc1a4664 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusServiceImpl.java @@ -0,0 +1,327 @@ +package com.bsd.pjcloud.thirdparty.service.impl.appplus; + +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +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.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.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.constant.pay.ThirdPayOrderBizTypeEnum; +import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderStatusEnum; +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppGetUniqueDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppOAth2LoginDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.ThirdMiniAppPayDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat.ThirdMiniJsapiPayDto; +import com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat.ThirdMiniWechatRefundDto; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.service.*; +import com.bsd.pjcloud.thirdparty.vo.appplus.ThirdMinAppOAth2LoginVo; +import com.bsd.pjcloud.thirdparty.vo.appplus.pay.ThirdMiniAppPayVo; +import com.bsd.pjcloud.thirdparty.vo.appplus.pay.wechat.*; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePaySuccess; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundSuccess; +import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargePackageEntity; +import com.bsd.pjcloud.wallet.api.feign.RemoteWalletRechargePackageService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Map; + +/** + * 小程序(小程序版本) + */ +@Service +@Validated +@Slf4j +@RequiredArgsConstructor +public class ThirdAppPlusServiceImpl implements ThirdAppPlusService { + + static private final String TAG = "小程序服务类"; + + private final ThirdAppPlusWechatService thirdMiniAppWechatService; + private final ThirdAppPlusAliPayService thirdMiniAppAliPayService; + private final ThirdPayLogService thirdPayLogService; + private final ThirdPayOrderService thirdPayOrderService; + + private final RemoteUserService remoteUserService; + private final RemoteTokenService remoteTokenService; + private final RemoteAppUserService remoteAppUserService; + private final RemoteWalletRechargePackageService remoteWalletRechargePackageService; + + /** + * 小程序登录 + */ + @Override + public ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto) { + ThirdMinAppOAth2LoginVo vo = new ThirdMinAppOAth2LoginVo(); + // 微信小程序 + if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) { + // 获取手机号 + WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getPhoneCode()); + if (ObjectUtil.isEmpty(phoneInfo)) { + vo.setErrorCode(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType()); + return vo; + } + // 根据手机号查询用户 + UserInfo userInfo = remoteUserService.getInnerByPhone(phoneInfo.getPurePhoneNumber()).getData(); + if (ObjectUtil.isEmpty(userInfo)) { + 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)) { + vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType()); + return vo; + } + vo.setAccessToken(dataMap.getOrDefault("accessToken", "")); + vo.setRefreshToken(dataMap.getOrDefault("refreshToken", "")); + } + // 支付宝 + else if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.ALI_PAY.getType())) { + + } + 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; + } + + /** + * 小程序支付 + */ + @Override + public ThirdMiniAppPayVo miniPay(Long userId, ThirdMiniAppPayDto dto) { + ThirdMiniAppPayVo result = new ThirdMiniAppPayVo(); + + if (ObjectUtil.equals(dto.getBizType(), ThirdPayOrderBizTypeEnum.MINI_APP_WALLET_RECHARGE)) { + Long bizId = null; + try { + bizId = Long.valueOf(dto.getBizId()); + } catch (Exception e) { + throw new RuntimeException("充值业务id解析错误"); + } + // 查询充值配置 + WalletRechargePackageEntity walletPackage = remoteWalletRechargePackageService.remoteGetById(bizId).getData(); + if (ObjectUtil.isEmpty(walletPackage)) { + throw new RuntimeException("错误的充值配置"); + } + int price = walletPackage.getPayPrice(); + if (price <= 0) { + throw new RuntimeException("错误的充值配置"); + } + dto.setAmount(price); + } + // 不支持的类型 + else { + throw new RuntimeException("不支持的支付类型"); + } + try { + // 微信小程序 + if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) { + ThirdMiniJsapiPayDto wechatPayDto = new ThirdMiniJsapiPayDto(); + // 当前时间戳+10位随机字符串 + String outTradeNo = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + RandomUtil.randomString(10); + wechatPayDto.setOutTradeNo(outTradeNo); + wechatPayDto.setBizId(dto.getBizId()); + wechatPayDto.setBizType(dto.getBizType()); + wechatPayDto.setUserId(userId); + wechatPayDto.setOpenid(dto.getOpenId()); + wechatPayDto.setAmount(dto.getAmount()); + ThirdMiniJsapiPayVo thirdMiniJsapiPayVo = thirdMiniAppWechatService.jsapiPay(wechatPayDto); + if (ObjectUtil.isEmpty(thirdMiniJsapiPayVo)) { + throw new RuntimeException("创建微信支付错误"); + } + result.setMiniAppPayParams(thirdMiniJsapiPayVo.getMiniAppPayParams()); + } + // 支付宝 + else if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.ALI_PAY.getType())) { + + } + // 不支持的支付类型 + else { + throw new RuntimeException("不支持的支付类型"); + } + } catch (Exception e) { + + } + return result; + } + + /** + * 小程序退款 + */ + @Override + public ThirdMiniAppPayVo miniRefund(ThirdMiniWechatRefundDto dto) { + // 查询详情 + ThirdPayOrderEntity thirdPayOrder = thirdPayOrderService.getByPayNo(dto.getPayNo()); + if (ObjectUtil.isEmpty(thirdPayOrder)) { + log.error("|{}|小程序退款错误,订单不存在dto:|{}|", TAG, JSONUtil.toJsonStr(dto)); + throw new RuntimeException("订单不存在"); + } + // 微信小程序 + if (ObjectUtil.equals(thirdPayOrder.getPayPlatformType(), MiniPlatformTypeEnum.WECHAT.getType())) { + thirdMiniAppWechatService.refund(thirdPayOrder, dto); + } + // 支付宝 + else if (ObjectUtil.equals(thirdPayOrder.getPayPlatformType(), MiniPlatformTypeEnum.ALI_PAY.getType())) { + + } + // 不支持的支付类型 + else { + throw new RuntimeException("不支持的支付类型"); + } + return null; + } + + /** + * 小程序支付回调 + */ + @Override + public String miniPayCallback(String body, Map headers) { + MiniPlatformTypeEnum platformType = checkMiniPlatformType(body); + // 微信小程序 + if (ObjectUtil.equals(platformType, MiniPlatformTypeEnum.WECHAT)) { + ThirdPayOrderEntity thirdPayOrder = thirdMiniAppWechatService.payCallback(body, headers); + if (ObjectUtil.isEmpty(thirdPayOrder)) { + return ThirdMiniWechatQueryVo.wechantError(); + } + // 根据订单bizType来处理 + boolean isSuccess = disposePaySuccessAfter(thirdPayOrder); + return isSuccess ? ThirdMiniWechatQueryVo.wechantSuccess() : ThirdMiniWechatQueryVo.wechantError(); + } + // 支付宝 + else if (ObjectUtil.equals(platformType, MiniPlatformTypeEnum.ALI_PAY)) { + return null; + } + // 不支持的支付类型 + else { + return null; + } + } + + /** + * 小程序退款回调 + */ + @Override + public String miniRefundCallback(String body, Map headers) { + MiniPlatformTypeEnum platformType = checkRefundMiniPlatformType(body); + // 微信小程序 + if (ObjectUtil.equals(platformType, MiniPlatformTypeEnum.WECHAT)) { + ThirdPayOrderEntity thirdPayOrder = thirdMiniAppWechatService.refundCallback(body, headers); + if (ObjectUtil.isEmpty(thirdPayOrder)) { + return ThirdMiniWechantRefunCallbackVo.wechantError(); + } + // 根据订单bizType来处理 + boolean isSuccess = disposeRefundSuccessAfter(thirdPayOrder); + return isSuccess ? ThirdMiniWechatQueryVo.wechantSuccess() : ThirdMiniWechatQueryVo.wechantError(); + } + // 支付宝 + else if (ObjectUtil.equals(platformType, MiniPlatformTypeEnum.ALI_PAY)) { + return null; + } + // 不支持的支付类型 + else { + return null; + } + } + + private MiniPlatformTypeEnum checkMiniPlatformType(String body) { + ThirdMiniWechatRefundQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(body)), ThirdMiniWechatRefundQueryVo.class); + // 查询订单 + if (ObjectUtil.isNotEmpty(vo) && ObjectUtil.isNotEmpty(vo.getTransaction_id())) { + return MiniPlatformTypeEnum.WECHAT; + } + return null; + } + + private MiniPlatformTypeEnum checkRefundMiniPlatformType(String body) { + ThirdMiniWechantRefunCallbackSoureVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(body)), ThirdMiniWechantRefunCallbackSoureVo.class); + // 查询订单 + if (ObjectUtil.isNotEmpty(vo) && ObjectUtil.isNotEmpty(vo.getAppid()) && ObjectUtil.isNotEmpty(vo.getMch_id()) && ObjectUtil.isNotEmpty(vo.getNonce_str()) && ObjectUtil.isNotEmpty(vo.getReq_info())) { + return MiniPlatformTypeEnum.WECHAT; + } + return null; + } + + public boolean disposePaySuccessAfter(ThirdPayOrderEntity thirdPayOrder) { + if (ObjectUtil.notEqual(thirdPayOrder.getStatus(), ThirdPayOrderStatusEnum.PAY_SUCCESS.getType())) { + return true; + } + // 已经支付 + try { + WalletRechargePaySuccess dto = new WalletRechargePaySuccess(); + dto.setPayNo(thirdPayOrder.getPayNo()); + dto.setUserId(thirdPayOrder.getUserId()); + dto.setBizId(thirdPayOrder.getBizId()); + dto.setBizType(thirdPayOrder.getBizType()); + return remoteWalletRechargePackageService.remotePaySuccess(dto).getData(); + } catch (Exception e) { + log.error("处理小程序支付成功回调异常", e); + return false; + } + } + + private boolean disposeRefundSuccessAfter(ThirdPayOrderEntity thirdPayOrder) { + if (ObjectUtil.notEqual(thirdPayOrder.getStatus(), ThirdPayOrderStatusEnum.REFUND_SUCCESS.getType())) { + return true; + } + // 已退款 + try { + WalletRechargeRefundSuccess dto = new WalletRechargeRefundSuccess(); + dto.setRefundNo(thirdPayOrder.getRefundNo()); + dto.setUserId(thirdPayOrder.getUserId()); + dto.setBizId(thirdPayOrder.getBizId()); + dto.setBizType(thirdPayOrder.getBizType()); + return remoteWalletRechargePackageService.remoteRefundSuccess(dto).getData(); + } catch (Exception e) { + log.error("处理小程序退款成功回调异常", e); + return false; + } + } + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImpl.java new file mode 100644 index 000000000..fa3fe5d5a --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImpl.java @@ -0,0 +1,546 @@ +package com.bsd.pjcloud.thirdparty.service.impl.appplus; + +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.AppPlusPayConfig; +import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum; +import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderStatusEnum; +import com.bsd.pjcloud.thirdparty.dto.appplus.pay.wechat.*; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.service.ThirdAppPlusWechatService; +import com.bsd.pjcloud.thirdparty.service.ThirdPayOrderService; +import com.bsd.pjcloud.thirdparty.utils.pay.wechat.ThirdAppPlusWechantPayConstant; +import com.bsd.pjcloud.thirdparty.vo.appplus.pay.wechat.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +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.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * 微信小程序(小程序版本) + */ +@Service +@Validated +@Slf4j +@RequiredArgsConstructor +public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService { + + private final String TAG = "微信小程序支付(小程序版本)"; + + private final AppPlusPayConfig appPlusPayConfig; + + private final WxMaService wxMaService; + private final ThirdPayOrderService thirdPayOrderService; + + + /** + * JSAPI/小程序下单 + */ + @Override + public ThirdMiniJsapiPayVo jsapiPay(ThirdMiniJsapiPayDto dto) { + AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.getWechatConfig(); + + ThirdPayOrderEntity payOrder = new ThirdPayOrderEntity(); + payOrder.setPayPlatformType(MiniPlatformTypeEnum.WECHAT.getType()); + payOrder.setBizId(dto.getBizId()); + payOrder.setBizType(dto.getBizType().getType()); + payOrder.setUserId(dto.getUserId()); + payOrder.setUserCode(dto.getOpenid()); + payOrder.setPrice(dto.getAmount()); + payOrder.setStatus(ThirdPayOrderStatusEnum.PAY_UNPAID.getType()); + payOrder.setPayNo(dto.getOutTradeNo()); + 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("body", "浦江数勤-钱包充值"); + // 商户订单号 + params.put("out_trade_no", dto.getOutTradeNo()); + // 商户回调地址 + params.put("notify_url", wechatConfig.getPayCallbackUrl()); + // 订单总金额,单位为分 + params.put("total_fee", dto.getAmount()); + // 终端IP + params.put("spbill_create_ip", wechatConfig.getSpbillCreateIp()); + // 交易类型 + params.put("trade_type", "JSAPI"); + // 用户标识 + params.put("openid", dto.getOpenid()); + // 生成签名 + params.put("sign", generateSign(params)); + ThirdAppPlusWechantPayConstant.Api api = initApi(ThirdAppPlusWechantPayConstant.WECHAT_PAY); + + String xmlStr = XmlUtil.mapToXmlStr(params); + payOrder.setPayRep(JSONUtil.toJsonStr(params)); + + String res = api.getHttpRequest().body(xmlStr).execute().body(); + log.debug("JSAPI/小程序下单,json,xml|{}", res); + if (ObjectUtil.isEmpty(res)) { + log.error("JSAPI/小程序下单,res为空"); + return null; + } + String jsonVo = JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)); + ThirdMiniJsapiPayVo vo = JSONUtil.toBean(jsonVo, ThirdMiniJsapiPayVo.class); + log.debug("|{}|JSAPI/小程序下单,json,res|{}", TAG, JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + payOrder.setPayTime(LocalDateTime.now()); + payOrder.setPayRes(jsonVo); + // 生成小程序 paySign + String nonceStr = RandomUtil.randomString(32); + long timeStamp = System.currentTimeMillis() / 1000; + String payPackage = "prepay_id=" + vo.getPrepay_id(); + String signType = "MD5"; + + String payStr = "appId=" + wechatConfig.getAppId() + "&"; + payStr += "nonceStr=" + nonceStr + "&"; + payStr += "package=" + payPackage + "&"; + payStr += "signType=" + signType + "&"; + payStr += "timeStamp=" + timeStamp + "&"; + payStr += "key=" + wechatConfig.getApiV2Key(); + String paySign = DigestUtils.md5Hex(payStr); + + HashMap miniAppPayParams = new HashMap<>(); + miniAppPayParams.put("timeStamp", timeStamp); + miniAppPayParams.put("nonceStr", nonceStr); + miniAppPayParams.put("package", payPackage); + miniAppPayParams.put("signType", signType); + miniAppPayParams.put("paySign", paySign); + vo.setMiniAppPayParams(miniAppPayParams); + return vo; + } catch (Exception e) { + log.error("|{}|JSAPI/小程序下单,异常", TAG, e); + return null; + } finally { + thirdPayOrderService.save(payOrder); + } + } + + /** + * 获取openId + */ + @Override + public String getOpenId(String code) { + try { + WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code); + if (ObjectUtil.isNotEmpty(session) && ObjectUtil.isNotEmpty(session.getOpenid())) { + return session.getOpenid(); + } + return null; + } catch (Exception e) { + e.printStackTrace(); + log.error("|{}|获取openId:{}", TAG, e.getMessage()); + return null; + } + } + + /** + * 获取手机号 + */ + @Override + public WxMaPhoneNumberInfo getPhone(String code) { + try { + WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(code); + if (ObjectUtil.isNotEmpty(phoneInfo)) { + return phoneInfo; + } + return null; + } catch (Exception e) { + e.printStackTrace(); + log.error("|{}|获取手机号:{}", TAG, e.getMessage()); + return null; + } + } + + /** + * 查询订单 + */ + @Override + public ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto) { + AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.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)); + ThirdAppPlusWechantPayConstant.Api api = initApi(ThirdAppPlusWechantPayConstant.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) { + AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.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)); + ThirdAppPlusWechantPayConstant.Api api = initApi(ThirdAppPlusWechantPayConstant.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; + } + } + + private String getTransactionIdByThirdPayOrder(ThirdPayOrderEntity thirdPayOrder) { + if (ObjectUtil.isEmpty(thirdPayOrder) || ObjectUtil.isEmpty(thirdPayOrder.getPayRes())) { + return null; + } + String payRes = thirdPayOrder.getPayCallbackRes(); + ThirdMiniWechantRefunCallbackVo thirdMiniJsapiPay = JSONUtil.toBean(payRes, ThirdMiniWechantRefunCallbackVo.class); + return thirdMiniJsapiPay.getTransaction_id(); + } + + /** + * 申请退款 + */ + @Override + public ThirdMiniWechatRefundVo refund(ThirdPayOrderEntity thirdPayOrder, ThirdMiniWechatRefundDto dto) { + AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.getWechatConfig(); + + ThirdPayOrderEntity updateObj = new ThirdPayOrderEntity(); + updateObj.setId(thirdPayOrder.getId()); + + Integer refundFee = dto.getRefundPrice(); + if (ObjectUtil.isEmpty(refundFee)) { + refundFee = thirdPayOrder.getPrice(); + } + String refundNo = "refund_" + thirdPayOrder.getPayNo(); + 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", getTransactionIdByThirdPayOrder(thirdPayOrder)); + // 商户订单号 + params.put("out_trade_no", thirdPayOrder.getPayNo()); + // 商户退款单号 + params.put("out_refund_no", refundNo); + // 订单金额 + params.put("total_fee", thirdPayOrder.getPrice()); + // 退款金额 + params.put("refund_fee", refundFee); + // 退款结果通知url + params.put("notify_url", wechatConfig.getRefundCallbackUrl()); + // 生成签名 + params.put("sign", generateSign(params)); + ThirdAppPlusWechantPayConstant.Api api = initApi(ThirdAppPlusWechantPayConstant.REFUND); + api.setSslSocketFactory(createSSLSocketFactory()); + + updateObj.setRefundRep(JSONUtil.toJsonStr(params)); + String xmlStr = XmlUtil.mapToXmlStr(params); + + String res = api.getHttpRequest().body(xmlStr).execute().body(); + log.debug("|{}|申请退款,json,xml|{}", TAG, res); + if (ObjectUtil.isEmpty(res)) { + log.error("|{}|申请退款,res为空", TAG); + return null; + } + String jsonVo = JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)); + updateObj.setRefundRes(jsonVo); + ThirdMiniWechatRefundVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundVo.class); + log.debug("|{}|申请退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo)); + if (!vo.isHttpSucess()) { + return null; + } + updateObj.setRefundNo(refundNo); + updateObj.setRefundTime(LocalDateTime.now()); + updateObj.setStatus(ThirdPayOrderStatusEnum.REFUNDING.getType()); + return vo; + } catch (Exception e) { + log.error("|{}|申请退款,异常", TAG, e); + return null; + } finally { + thirdPayOrderService.updateById(updateObj); + } + } + + /** + * 查询退款 + */ + @Override + public ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto) { + AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.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)); + ThirdAppPlusWechantPayConstant.Api api = initApi(ThirdAppPlusWechantPayConstant.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 ThirdPayOrderEntity payCallback(String body, Map headers) { + String bodyJson = JSONUtil.toJsonStr(XmlUtil.xmlToMap(body)); + ThirdMiniWechatRefundQueryVo vo = JSONUtil.toBean(bodyJson, ThirdMiniWechatRefundQueryVo.class); + if (ObjectUtil.isEmpty(vo) || !vo.isHttpSucess()) { + return null; + } + boolean paySucess = vo.isPaySucess(); + // 查询订单 + ThirdPayOrderEntity payOrderEntity = thirdPayOrderService.getByPayNo(vo.getOut_trade_no()); + if (ObjectUtil.isEmpty(payOrderEntity)) { + log.error("|{}|payCallback,意外的错误,订单不存在,微信返回json|{}|", TAG, bodyJson); + return null; + } + // 重复的回调 + if (ObjectUtil.notEqual(payOrderEntity.getStatus(), ThirdPayOrderStatusEnum.PAY_UNPAID.getType())) { + log.error("|{}|payCallback,意外的错误,重复的回调,微信返回json|{}|", TAG, bodyJson); + return null; + } + // 更新订单状态 + ThirdPayOrderEntity updateObj = new ThirdPayOrderEntity(); + updateObj.setId(payOrderEntity.getId()); + updateObj.setPayCallbackRes(bodyJson); + updateObj.setStatus(paySucess ? ThirdPayOrderStatusEnum.PAY_SUCCESS.getType() : ThirdPayOrderStatusEnum.PAY_FAILED.getType()); + thirdPayOrderService.updateById(updateObj); + return thirdPayOrderService.getById(payOrderEntity.getId()); + } + + /** + * 退款回调 + */ + @Override + public ThirdPayOrderEntity refundCallback(String body, Map headers) { + ThirdMiniWechantRefunCallbackVo vo = decrypt(body); + if (ObjectUtil.isEmpty(vo)) { + return null; + } + // 查询订单 + ThirdPayOrderEntity payOrderEntity = thirdPayOrderService.getByPayNo(vo.getOut_trade_no()); + if (ObjectUtil.isEmpty(payOrderEntity)) { + log.error("|{}|refundCallback,意外的错误,订单不存在,微信返回json|{}|", TAG, JSONUtil.toJsonStr(vo)); + return null; + } + // 重复的回调 + if (ObjectUtil.notEqual(payOrderEntity.getStatus(), ThirdPayOrderStatusEnum.REFUNDING.getType())) { + log.error("|{}|refundCallback,意外的错误,重复的回调,微信返回json|{}|", TAG, JSONUtil.toJsonStr(vo)); + return null; + } + // 更新订单状态 + boolean refundSuccess = vo.isAllSuccess(); + ThirdPayOrderEntity updateObj = new ThirdPayOrderEntity(); + updateObj.setId(payOrderEntity.getId()); + updateObj.setRefundCallbackRes(JSONUtil.toJsonStr(vo)); + updateObj.setStatus(refundSuccess ? ThirdPayOrderStatusEnum.REFUND_SUCCESS.getType() : ThirdPayOrderStatusEnum.REFUND_FAILED.getType()); + thirdPayOrderService.updateById(updateObj); + return thirdPayOrderService.getById(payOrderEntity.getId()); + } + + /** + * 解密回调信息解密 + */ + private ThirdMiniWechantRefunCallbackVo decrypt(String xml) { + AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.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 = appPlusPayConfig.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 ThirdAppPlusWechantPayConstant.Api initApi(ThirdAppPlusWechantPayConstant.Api api) { + api.setBaseUrl(appPlusPayConfig.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(appPlusPayConfig.getWechatConfig().getMerchantSerialPath()); + keyStore.load(certStream, appPlusPayConfig.getWechatConfig().getMerchantId().toCharArray()); + certStream.close(); + // 创建KeyManagerFactory + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, appPlusPayConfig.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/service/impl/pay/ThirdPayOrderServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdPayOrderServiceImpl.java new file mode 100755 index 000000000..44c124e94 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdPayOrderServiceImpl.java @@ -0,0 +1,65 @@ +package com.bsd.pjcloud.thirdparty.service.impl.pay; + +import cn.hutool.core.collection.IterUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bsd.pjcloud.admin.api.entity.SysUser; +import com.bsd.pjcloud.admin.api.feign.RemoteUserService; +import com.bsd.pjcloud.common.data.datascope.DataScope; +import com.bsd.pjcloud.thirdparty.dto.pay.ThirdPayOrderDto; +import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; +import com.bsd.pjcloud.thirdparty.mapper.pay.ThirdPayOrderMapper; +import com.bsd.pjcloud.thirdparty.service.ThirdPayOrderService; +import com.bsd.pjcloud.thirdparty.vo.pay.ThirdPayOrderVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * 第三方支付订单 + */ +@Service +@Validated +@Slf4j +@RequiredArgsConstructor +public class ThirdPayOrderServiceImpl extends ServiceImpl implements ThirdPayOrderService { + + private final RemoteUserService remoteUserService; + + @Override + public Page scopePage(Page page, ThirdPayOrderDto dto, DataScope dataScope) { + Page pageList = baseMapper.scopePage(page, dto, dataScope); + disposePageList(pageList.getRecords(), dto); + return pageList; + } + + @Override + public ThirdPayOrderEntity getByPayNo(String payNo) { + return getOne(new LambdaQueryWrapper().eq(ThirdPayOrderEntity::getPayNo, payNo)); + } + + private void disposePageList(List list, ThirdPayOrderDto dto) { + if (ObjectUtil.isEmpty(list)) return; + // 查询用户 + List userIdList = list.stream().map(ThirdPayOrderEntity::getUserId).filter(ObjectUtil::isNotEmpty).distinct().toList(); + if (ObjectUtil.isNotEmpty(userIdList)) { + List userList = remoteUserService.getInnerUserById(userIdList).getData(); + if (ObjectUtil.isNotEmpty(userList)) { + Map userMap = IterUtil.toMap(userList, SysUser::getUserId); + for (ThirdPayOrderVo user : list) { + SysUser targetUser = userMap.get(user.getUserId()); + if (ObjectUtil.isEmpty(targetUser)) continue; + user.setUsername(targetUser.getName()); + user.setUserPhone(targetUser.getPhone()); + } + } + } + } + +} \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/pay/wechat/ThirdAppPlusWechantPayConstant.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/pay/wechat/ThirdAppPlusWechantPayConstant.java new file mode 100644 index 000000000..e7f6b2fb8 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/pay/wechat/ThirdAppPlusWechantPayConstant.java @@ -0,0 +1,65 @@ +package com.bsd.pjcloud.thirdparty.utils.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 + */ +public class ThirdAppPlusWechantPayConstant { + + public static final Api WECHAT_PAY = Api.builder().summary("微信小程序支付").url("/pay/unifiedorder").method(HttpMethod.POST).isNeedCertificate(false).build(); + + 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 674897636..beaf3f112 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml @@ -89,23 +89,37 @@ zy: # callback-recognition-url: /third/third-ks/callback/recognition # callback-sku-url: /third/third-ks/callback/sku # lb: - # 测试环境 - # base-url: https://elss-sit.nbcb.com.cn - # app-id: 7da62b1a9ade473c917f573c5748081e - # app-secret: 8ffI6b+OKTmdVAt9Qo+2F/HQQMdt/d8GFia0zlJOt9I= - # company-number: 202504673472 - # sm4-key: S67157e8aQs2tFSX +# 测试环境 +# base-url: https://elss-sit.nbcb.com.cn +# app-id: 7da62b1a9ade473c917f573c5748081e +# app-secret: 8ffI6b+OKTmdVAt9Qo+2F/HQQMdt/d8GFia0zlJOt9I= +# company-number: 202504673472 +# sm4-key: S67157e8aQs2tFSX - # 正式环境 - # base-url: https://elss.nbcb.com.cn - # app-id: 528e3ca76ec34f5c9b3255ba18aee774 - # app-secret: tIhDZDXWhtP6bvd0J9Q0zjIZxSkmyX+uUc87xnDTgfc= - # company-number: 202504673472 - # sm4-key: 63P839eg0uxE5aoG +# 正式环境 +# base-url: https://elss.nbcb.com.cn +# app-id: 528e3ca76ec34f5c9b3255ba18aee774 +# app-secret: tIhDZDXWhtP6bvd0J9Q0zjIZxSkmyX+uUc87xnDTgfc= +# company-number: 202504673472 +# sm4-key: 63P839eg0uxE5aoG ad: uni-ad-callback-secret: ee2b40b8b399d2416c4c2df9cca7344adf9838dc179af5360bc52be410020428 +app-plus: + pay: + wechat-config: + app-id: wx11771c7bf2913cb2 + app-secret: a6b0d036b229117595687a7c1705d332 + merchant-id: 1106210589 + api-v2-key: qr0w9WkAu6GG3uuxPjDT7bcdIVoBr0rw + merchant-serial-path: /Users/dengzhangchen/Desktop/backups/pay/third_cert/apiclient_cert.p12 + pay-callback-url: https://dzc-test-1.fy.takin.cc/third/third-mini-app-pay/app/pay-callback + refund-callback-url: https://dzc-test-1.fy.takin.cc/third/third-mini-app-pay/app/refund-callback + spbill-create-ip: 59.202.170.152 + base-url: https://api.mch.weixin.qq.com + ali-pay-config: + app-id: sms: api: @@ -132,7 +146,7 @@ sms: 27694: content: "{yyName}邀请您于{visitorTime}访问{deptName},为保障您的顺利通行,请通过地址:{url} 查看详情。" - params: ["yyName", "visitorTime", "deptName", "url" ] + params: [ "yyName", "visitorTime", "deptName", "url" ] 30758: content: "阿姨您好!{meetingName}于{meetingDate}开始会议,桌子拜访形态{deskType},请提前安排整理工作!" diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/mapper/ThirdPayOrderMapper.xml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/mapper/ThirdPayOrderMapper.xml new file mode 100644 index 000000000..4200b3807 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/mapper/ThirdPayOrderMapper.xml @@ -0,0 +1,66 @@ + + + + + + select a.id, + a.pay_platform_type, + a.biz_type, + a.biz_id, + a.user_id, + a.user_code, + a.price, + a.status, + a.pay_no, + a.pay_time, + a.pay_rep, + a.pay_res, + a.pay_callback_res, + a.refund_no, + a.refund_time, + a.refund_rep, + a.refund_res, + a.refund_callback_res, + a.expire_time, + a.create_time, + a.update_time, + a.create_by, + a.update_by, + a.del_flag, + a.tenant_id + + + + a.del_flag = '0' + + and a.pay_no LIKE concat('%',#{dto.payNo},'%') + + + and a.id = #{dto.id} + + + and a.pay_platform_type = #{dto.payPlatformType} + + + and a.biz_type = #{dto.bizType} + + + and a.user_id = #{dto.userId} + + + and a.pay_time between #{dto.payTimeList[0]} and #{dto.payTimeList[1]} + + + and a.refund_time between #{dto.refundTimeList[0]} and #{dto.refundTimeList[1]} + + + + + \ No newline at end of file diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargePaySuccess.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargePaySuccess.java new file mode 100644 index 000000000..25518965b --- /dev/null +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargePaySuccess.java @@ -0,0 +1,28 @@ +package com.bsd.pjcloud.wallet.api.dto.recharge; + +import lombok.Data; + +@Data +public class WalletRechargePaySuccess { + + /** + * 订单号 + */ + private String payNo; + + /** + * 用户id + */ + private Long userId; + + /** + * 业务类型 + */ + private String bizType; + + /** + * 业务id + */ + private String bizId; + +} diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeRefundSuccess.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeRefundSuccess.java new file mode 100644 index 000000000..a89f6330e --- /dev/null +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeRefundSuccess.java @@ -0,0 +1,28 @@ +package com.bsd.pjcloud.wallet.api.dto.recharge; + +import lombok.Data; + +@Data +public class WalletRechargeRefundSuccess { + + /** + * 订单号 + */ + private String refundNo; + + /** + * 用户id + */ + private Long userId; + + /** + * 业务类型 + */ + private String bizType; + + /** + * 业务id + */ + private String bizId; + +} diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/feign/RemoteWalletRechargePackageService.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/feign/RemoteWalletRechargePackageService.java new file mode 100644 index 000000000..7507bcd5e --- /dev/null +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/feign/RemoteWalletRechargePackageService.java @@ -0,0 +1,28 @@ +package com.bsd.pjcloud.wallet.api.feign; + +import com.bsd.pjcloud.common.core.constant.ServiceNameConstants; +import com.bsd.pjcloud.common.core.util.R; +import com.bsd.pjcloud.common.feign.annotation.NoToken; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePaySuccess; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundSuccess; +import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargePackageEntity; +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 = "remoteWalletRechargePackageService", value = ServiceNameConstants.WALLET_SERVICE) +public interface RemoteWalletRechargePackageService { + + @GetMapping("/wallet-recharge-package/remote/{id}") + R remoteGetById(@PathVariable("id") Long id); + + @NoToken + @PostMapping("/wallet-recharge-package/remote/pay-success") + R remotePaySuccess(@RequestBody WalletRechargePaySuccess dto); + + @NoToken + @PostMapping("/wallet-recharge-package/remote/refund-success") + R remoteRefundSuccess(@RequestBody WalletRechargeRefundSuccess dto); +} diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports b/pjcloud-wallet/pjcloud-wallet-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports index c16eafd08..c56550d18 100644 --- a/pjcloud-wallet/pjcloud-wallet-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports @@ -8,6 +8,7 @@ com.bsd.pjcloud.wallet.api.feign.RemoteCodeUseService com.bsd.pjcloud.wallet.api.feign.RemoteWalletRechargeService com.bsd.pjcloud.wallet.api.feign.RemoteWalletRuleTransactionService com.bsd.pjcloud.wallet.api.feign.RemoteMchService +com.bsd.pjcloud.wallet.api.feign.RemoteWalletRechargePackageService com.bsd.pjcloud.wallet.api.feign.RemoteWalletSettingService com.bsd.pjcloud.wallet.api.feign.RemoteWalletThirdZyService com.bsd.pjcloud.wallet.api.feign.RemoteWalletTransactionService \ No newline at end of file diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargePackageController.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargePackageController.java index ce59a3604..40be97c68 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargePackageController.java +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargePackageController.java @@ -7,7 +7,10 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.log.annotation.SysLog; +import com.bsd.pjcloud.common.security.annotation.Inner; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePackageDto; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePaySuccess; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundSuccess; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargePackageEntity; import com.bsd.pjcloud.wallet.service.WalletRechargePackageService; import org.springframework.security.access.prepost.PreAuthorize; @@ -24,9 +27,6 @@ import java.util.List; /** * 充值套餐表 - * - * @author dzc - * @date 2025-01-03 18:33:55 */ @RestController @RequiredArgsConstructor @@ -37,6 +37,28 @@ public class WalletRechargePackageController { private final WalletRechargePackageService walletRechargePackageService; + /* ************************************* start remote start ************************************* */ + @Operation(summary = "通过id查询", description = "通过id查询") + @GetMapping("/remote/{id}") + public R remoteGetById(@PathVariable("id") Long id) { + return R.ok(walletRechargePackageService.getById(id)); + } + + @Inner + @Operation(summary = "支付成功", description = "支付成功") + @PostMapping("/remote/pay-success") + public R remotePaySuccess(@RequestBody WalletRechargePaySuccess dto) { + return R.ok(walletRechargePackageService.remotePaySuccess(dto)); + } + + @Inner + @Operation(summary = "退款成功", description = "退款成功") + @PostMapping("/remote/refund-success") + public R remoteRefundSuccess(@RequestBody WalletRechargeRefundSuccess dto) { + return R.ok(walletRechargePackageService.remoteRefundSuccess(dto)); + } + /* ************************************* end remote end ************************************* */ + /* ************************************* start app start ************************************* */ @Operation(summary = "查询全部", description = "查询全部") @GetMapping("/app/list") diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargePackageService.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargePackageService.java index 533f005c4..2cae25e7f 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargePackageService.java +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargePackageService.java @@ -3,17 +3,27 @@ package com.bsd.pjcloud.wallet.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePackageDto; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePaySuccess; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundSuccess; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargePackageEntity; import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargePackageVo; public interface WalletRechargePackageService extends IService { + /** + * 支付成功 + */ + Boolean remotePaySuccess(WalletRechargePaySuccess dto); + + /** + * 退款成功 + */ + Boolean remoteRefundSuccess(WalletRechargeRefundSuccess dto); + Page pageJoin(Page page, WalletRechargePackageDto dto); /** * 校验是否有效 - * @param packageId - * @return */ WalletRechargePackageEntity validEffective(Long packageId); } \ No newline at end of file diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargePackageServiceImpl.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargePackageServiceImpl.java index 90ba0ef42..1ebe1f801 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargePackageServiceImpl.java +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargePackageServiceImpl.java @@ -1,25 +1,114 @@ package com.bsd.pjcloud.wallet.service.impl.recharge; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum; +import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderBizTypeEnum; +import com.bsd.pjcloud.wallet.api.constant.WalletBizEnum; +import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePackageDto; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargePaySuccess; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundSuccess; +import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity; +import com.bsd.pjcloud.wallet.api.entity.WalletTransactionEntity; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargePackageEntity; import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargePackageVo; import com.bsd.pjcloud.wallet.mapper.recharge.WalletRechargePackageMapper; +import com.bsd.pjcloud.wallet.service.WalletManageService; import com.bsd.pjcloud.wallet.service.WalletRechargePackageService; +import com.bsd.pjcloud.wallet.service.WalletTransactionService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * 充值套餐表 - * - * @author dzc - * @date 2025-01-03 18:33:55 */ +@Slf4j @Service +@AllArgsConstructor public class WalletRechargePackageServiceImpl extends ServiceImpl implements WalletRechargePackageService { + static private final String TAG = "充值套餐"; + + private final WalletManageService walletManageService; + private final WalletTransactionService walletTransactionService; + + /** + * 支付成功的回调 + */ + @Override + public Boolean remotePaySuccess(WalletRechargePaySuccess dto) { + // 小程序用户钱包充值 + if (ObjectUtil.equals(dto.getBizType(), ThirdPayOrderBizTypeEnum.MINI_APP_WALLET_RECHARGE.getType())) { + // 查询充值套餐 + WalletRechargePackageEntity rechargePackage = baseMapper.selectById(dto.getBizId()); + if (ObjectUtil.isEmpty(rechargePackage)) { + log.error("{}支付成功的回调,充值套餐不存在,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + // 需要充值的金额 + Integer totalPrice = rechargePackage.getPayPrice() + rechargePackage.getBonusPrice(); + if (totalPrice <= 0) { + log.error("{}支付成功的回调,充值套餐金额<=0,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + // 查询这个用户的充值钱包 + WalletManageEntity topupWallet = walletManageService.getWallet(dto.getUserId(), WalletTypeEnum.EAT); + if (ObjectUtil.isEmpty(topupWallet)) { + log.error("{}支付成功的回调,查询这个用户的充值钱包,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + // 进行充值 + WalletTransactionEntity walletTransaction = walletTransactionService.addWalletBalance(topupWallet.getId(), totalPrice, dto.getPayNo(), WalletBizEnum.RECHARGE); + return ObjectUtil.isNotEmpty(walletTransaction); + } + // 不支持的类型 + else { + log.error("{}支付成功的回调,不支持的类型,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + } + + /** + * 退款成功的回调 + */ + @Override + public Boolean remoteRefundSuccess(WalletRechargeRefundSuccess dto) { + // 小程序用户钱包充值 + if (ObjectUtil.equals(dto.getBizType(), ThirdPayOrderBizTypeEnum.MINI_APP_WALLET_RECHARGE.getType())) { + // 查询充值套餐 + WalletRechargePackageEntity rechargePackage = baseMapper.selectById(dto.getBizId()); + if (ObjectUtil.isEmpty(rechargePackage)) { + log.error("{}退款成功的回调,充值套餐不存在,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + // 需要退款的金额 + Integer totalPrice = rechargePackage.getPayPrice() + rechargePackage.getBonusPrice(); + if (totalPrice <= 0) { + log.error("{}退款成功的回调,充值套餐金额<=0,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + // 查询这个用户的充值钱包 + WalletManageEntity topupWallet = walletManageService.getWallet(dto.getUserId(), WalletTypeEnum.EAT); + if (ObjectUtil.isEmpty(topupWallet)) { + log.error("{}退款成功的回调,查询这个用户的充值钱包,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + // 进行扣款预约扣款为负数 + WalletTransactionEntity walletTransaction = walletTransactionService.reduceWalletBalance(topupWallet.getId(), totalPrice, dto.getRefundNo(), WalletBizEnum.REFUND, true); + return ObjectUtil.isNotEmpty(walletTransaction); + } + // 不支持的类型 + else { + log.error("{}退款成功的回调,不支持的类型,dto:{}", TAG, JSONUtil.toJsonStr(dto)); + return false; + } + } + + @Override public Page pageJoin(Page page, WalletRechargePackageDto dto) { return baseMapper.pageJoin(page, dto);