ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/FinanceController.java
@@ -36,8 +36,8 @@ @PostMapping("/top") @ApiOperation(value = "财务流水-顶部") @PreAuthorize("@ss.hasPermi('finance:flows')") public R<FinanceFlowsTopVO> top(){ return R.ok(orderService.financeTop()); public R<FinanceFlowsTopVO> top(@RequestBody FinanceFlowsDTO dto){ return R.ok(orderService.financeTop(dto)); } /** ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/IndexController.java
@@ -19,6 +19,7 @@ import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; @Slf4j @@ -60,21 +61,25 @@ @ApiOperation(value = "收入统计-折线图") @PreAuthorize("@ss.hasPermi('index:manage')") public R<IndexLineChartVO> chart(@RequestParam(required = false, defaultValue = "7") Integer days, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd ") LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) { // 处理日期范围 LocalDate now = LocalDate.now(); if (startDate == null || endDate == null) { startDate = now.minusDays(days - 1); endDate = now; LocalDate start; LocalDate end ; if (startTime == null || endTime == null) { start = now.minusDays(days - 1); end = now; } else { // 验证日期范围不超过30天 long daysBetween = ChronoUnit.DAYS.between(startDate, endDate); long daysBetween = ChronoUnit.DAYS.between(startTime, endTime); start=startTime.toLocalDate(); end = endTime.toLocalDate(); if (daysBetween > 30) { endDate = startDate.plusDays(30); endTime = startTime.plusDays(30); } } return R.ok(orderService.chart(startDate,endDate)); return R.ok(orderService.chart(start,end)); } ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/OrderController.java
@@ -2,8 +2,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.utils.wx.RefundCallbackResult; import com.ruoyi.system.pojo.dto.AppUserPageDTO; import com.ruoyi.system.pojo.dto.OrderPageDTO; import com.ruoyi.system.pojo.vo.*; import com.ruoyi.system.service.OrderService; @@ -14,9 +12,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @Slf4j @RestController @@ -57,41 +53,41 @@ /** * todo redis 企业异常信息 * 企业异常信息 */ @GetMapping("/error/{id}") @ApiOperation(value = "查看详情-企业异常信息") @PreAuthorize("@ss.hasPermi('order:manage')") public R<ErrorVO> error(@PathVariable("id") String id) { return R.ok(orderService.error(id)); public R error(@PathVariable("id") String id) { return orderService.error(id); } /** * todo redis 企业变更信息 * 企业变更信息 */ @GetMapping("/change/{id}") @ApiOperation(value = "查看详情-企业变更信息") @PreAuthorize("@ss.hasPermi('order:manage')") public R<ChangeVO> change(@PathVariable("id") String id) { return R.ok(orderService.change(id)); public R change(@PathVariable("id") String id) { return orderService.change(id); } /** * todo redis 企业纳税信息 * 企业纳税信息 */ @GetMapping("/tax/{id}") @ApiOperation(value = "查看详情-企业纳税信息") @PreAuthorize("@ss.hasPermi('order:manage')") public R<TaxVO> tax(@PathVariable("id") String id) { return R.ok(orderService.tax(id)); public R tax(@PathVariable("id") String id) { return orderService.tax(id); } /** * todo redis 企业发票信息 * 企业发票信息 */ @GetMapping("/invoice/{id}") @ApiOperation(value = "查看详情-企业纳税信息") @ApiOperation(value = "查看详情-企业发票信息") @PreAuthorize("@ss.hasPermi('order:manage')") public R<InvoiceVO> invoice(@PathVariable("id") String id) { return R.ok(orderService.invoice(id)); public R invoice(@PathVariable("id") String id) { return orderService.invoice(id); } /** * 删除 @@ -127,28 +123,21 @@ return R.ok(); } /** * 订单取消支付回退 * * @param refundCallbackResult * @param response * 平台取消订单支付回退 * @return */ @ResponseBody @GetMapping("/refundPayMoneyCallback") public void refundPayMoneyCallback(RefundCallbackResult refundCallbackResult, HttpServletResponse response) { R callback = orderService.refundPayMoneyCallback(refundCallbackResult); @PostMapping("/refundPayMoneyCallback") public String refundPayMoneyCallback(@RequestBody(required = false) String xmlData) { System.out.println("平台取消订单:" + xmlData); R callback = orderService.refundPayMoneyCallback(xmlData); if (callback.getCode() == 200) { response.setStatus(200); PrintWriter out = null; try { out = response.getWriter(); } catch (IOException e) { throw new RuntimeException(e); } out.println("success"); out.flush(); out.close(); return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"; }else { System.err.println("支付回退错误:"+callback.getMsg()); return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>"; } } } ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/QuestionController.java
@@ -38,8 +38,8 @@ public R<IPage<QuestionPageVO>> getQuestionPage( @RequestParam(value = "pageNum",defaultValue = "1") Integer pageNum, @RequestParam(value = "pageSize",defaultValue = "10") Integer pageSize, @RequestParam(value = "name",required = false) String name) { return R.ok(questionService.getQuestionPage(pageNum,pageSize,name)); @RequestParam(value = "title",required = false) String title) { return R.ok(questionService.getQuestionPage(pageNum,pageSize,title)); } /** ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -48,6 +48,8 @@ @Autowired private TokenService tokenService; @Autowired private ISysConfigService configService; @@ -74,7 +76,7 @@ * * @return 用户信息 */ @GetMapping("getInfo") @GetMapping("/getInfo") public AjaxResult getInfo() { LoginUser loginUser = SecurityUtils.getLoginUser(); ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -1,7 +1,15 @@ package com.ruoyi.web.controller.system; import java.awt.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.system.mapper.SysMenuMapper; import com.ruoyi.system.pojo.dto.UpdatePwdDTO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -48,6 +56,8 @@ @Autowired private TokenService tokenService; @Autowired private SysMenuMapper sysMenuMapper; /** * 个人信息 @@ -61,8 +71,33 @@ AjaxResult ajax = AjaxResult.success(user); ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); ajax.put("permissions" ,getUserPaths(user.getUserId())); return ajax; } /** * 获取用户拥有的所有path * @param userId 用户ID * @return 用户拥有的所有path列表 */ public List<String> getUserPaths(Long userId) { List<Long> ids = new ArrayList<>(); // 根据用户id查询出menus List<SysMenu> menus = sysMenuMapper.selectMenusByUserId(userId); //将id和父类id取出 menus.forEach(menu -> { ids.add(menu.getMenuId()); if (null!= menu.getParentId() && menu.getParentId() != 0) { ids.add(menu.getParentId()); } }); if (menus.isEmpty()) { return Collections.emptyList(); } return sysMenuMapper.getPathsByMenuIds(ids); } /** * 修改用户 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -327,7 +327,7 @@ // 更新缓存用户权限 LoginUser loginUser = getLoginUser(); if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) { loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getPhonenumber())); loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); tokenService.setLoginUser(loginUser); } ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -270,9 +270,9 @@ @GetMapping("/page/list") public R<IPage<SysUserPageListVO>> getSysUserPageList(@RequestParam("pageNum")Integer pageNum, @RequestParam("pageSize")Integer pageSize, @RequestParam("nickName")String nickName, @RequestParam("phone")Integer phone, @RequestParam("status")String status) { @RequestParam(value = "nickName",required = false)String nickName, @RequestParam(value = "phone",required = false)Integer phone, @RequestParam(value = "status",required = false)String status) { IPage<SysUserPageListVO> page=new Page<>(pageNum,pageSize); return R.ok(userService.getSysUserPageList(page,nickName,phone,status)); } @@ -310,7 +310,7 @@ /** * 新增 */ @ApiOperation(value = "账号管理-查看详情(回显)", tags = "系统后台-权限管理") @ApiOperation(value = "账号管理-新增", tags = "系统后台-权限管理") @PreAuthorize("@ss.hasPermi('permission:account')") @Log(title = "账号管理", businessType = BusinessType.INSERT) @PostMapping("/add") ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SystemConfigController.java
@@ -34,7 +34,7 @@ * 系统配置-查看 */ @GetMapping("/getSystemConfigByType") @ApiOperation(value = "根据类型获取配置内容") @ApiOperation(value = "根据类型获取配置内容(1-启动页 2-客服 3-抽单)") public R<SystemConfigVO> getSystemConfigByType(@RequestParam(value = "type") Integer type) { return R.ok(systemConfigService.getSystemConfigByType(type)); } ruoyi-admin/src/main/resources/application.yml
@@ -16,7 +16,7 @@ # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8081 port: 8084 servlet: # 应用的访问路径 context-path: / @@ -94,8 +94,8 @@ header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 30 # 令牌有效期(默认72000分钟) expireTime: 72000 # MyBatis配置 mybatis: @@ -117,7 +117,7 @@ # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api pathMapping: # 防止XSS攻击 xss: @@ -127,3 +127,12 @@ excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* wx: appid: wx180c41e1915992e8 appletsAppSecret: 8c6cc3410891d3096988b92c154ba5e9 mchId: 1720552698 key: 5Kb8zX9qR3r4D7Yw3vHnJgLp6sA4cE1M callbackPath: http://221.182.45.100:8084 certPath: classpath:cert/apiclient_cert.p12 RASPath: ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -178,11 +178,12 @@ } public static void main(String[] args) { System.out.println("19923261698".substring(5, 11)); String hash = Md5Utils.hash("123456"); System.out.println(hash); System.out.println(encryptPassword(hash)); System.out.println(matchesPassword(hash, "$2a$10$VhdvkOtOTUq1NndvwPC36./D9bPVhDJWbt.tVWtGdqW3.sA07Ikx.")); System.out.println(matchesPassword(hash, "$2a$10$rk6XzddjDljPCCTghplExe2rgcLCJHVEEOAOuUaHalsIp/FCWObkG")); } } ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/CloseOrderResult.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/FrpCodeEnum.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/PaymentUtil.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/QueryOrderResult.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/QueryRefundResult.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/RefundCallbackResult.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/RefundResult.java
File was deleted ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/UniPayResult.java
File was deleted ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -29,6 +29,8 @@ import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysUserService; import java.util.List; /** * 登录校验方法 * ruoyi-system/pom.xml
@@ -22,6 +22,16 @@ <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common</artifactId> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> </dependencies> ruoyi-system/src/main/java/com/ruoyi/system/domain/Qichacha.java
@@ -1,9 +1,12 @@ package com.ruoyi.system.domain; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDateTime; import java.util.Date; @Data @@ -21,5 +24,6 @@ @TableField(value = "time") @ApiModelProperty(value = "调用时间") private Date time; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime time; } ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderMapper.java
@@ -27,7 +27,7 @@ List<DailyStatistics> getDailyStatistics(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime); FinanceFlowsTopVO financeTop(); FinanceFlowsTopVO financeTop(@Param("dto") FinanceFlowsDTO dto); IPage<FinanceFlowsPageVO> flowsPage(@Param("page") IPage<FinanceFlowsPageVO> page, @Param("dto")FinanceFlowsDTO dto); ruoyi-system/src/main/java/com/ruoyi/system/mapper/QuestionMapper.java
@@ -12,5 +12,5 @@ @Mapper public interface QuestionMapper extends BaseMapper<Question> { IPage<QuestionPageVO> getQuestionPage(@Param("page")IPage<BannerPageVO> page,@Param("name") String name); IPage<QuestionPageVO> getQuestionPage(@Param("page")IPage<BannerPageVO> page,@Param("title") String title); } ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
@@ -128,4 +128,9 @@ List<MenuTreeVO> selectMenusByParentId(@Param("menuId")Long menuId); List<MenuTreeVO> getAllRootMenu(); List<SysMenu> selectMenusByUserId(@Param("userId")Long userId); List<String> getPathsByMenuIds(@Param("ids")List<Long> ids); } ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -134,7 +134,7 @@ IPage<SysUserPageListVO> getSysUserPageList(@Param("page") IPage<SysUserPageListVO> page, @Param("nickName") String nickName,@Param("phone") Integer phone, @Param("status") String status); R<SysUserVO> getSysUserVO(@Param("userId") Long userId); SysUserVO getSysUserVO(@Param("userId") Long userId); SysUser selectuserByPhone(@Param("phonenumber") String phonenumber); } ruoyi-system/src/main/java/com/ruoyi/system/pojo/dto/AppUserPageDTO.java
@@ -15,7 +15,7 @@ @ApiModelProperty("分页大小") private Integer pageSize=10; @ApiModelProperty("用户姓名") private String username; private String userName; @ApiModelProperty("联系电话") private String phone; @ApiModelProperty("状态") ruoyi-system/src/main/java/com/ruoyi/system/pojo/dto/FinanceFlowsDTO.java
@@ -21,8 +21,8 @@ private String orderNo; @ApiModelProperty(value = "类型:0-全部 1-收入 2-退款") private Integer type = 0; @ApiModelProperty(value = "类型: 1-收入 2-退款") private Integer type ; @ApiModelProperty(value = "操作时间-开始") @@ -34,4 +34,7 @@ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime operateTimeEnd; @ApiModelProperty(hidden = true) private Integer offset; } ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/ChangeVO.java
@@ -1,9 +1,18 @@ package com.ruoyi.system.pojo.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.List; @Data @ApiModel("企业变更信息") public class ChangeVO { @ApiModelProperty("银税互动授权记录") private List<Object> bankAndTaxInteractive; @ApiModelProperty("股东明细") private List<Object> sharesRatioList; @ApiModelProperty("法人/股东变更") private List<Object> legalPersonGdChange; } ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/ErrorVO.java
@@ -1,10 +1,17 @@ package com.ruoyi.system.pojo.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; import lombok.Data; import java.util.List; @Data @ApiModel("企业异常信息VO") public class ErrorVO { @ApiModelProperty("数据是否存在(1-存在 0-不存在)") private Integer VerifyResult; @ApiModelProperty("数据信息") private Object Data; } ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/InvoiceVO.java
@@ -1,9 +1,73 @@ package com.ruoyi.system.pojo.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data @ApiModel("企业发票信息") public class InvoiceVO { @ApiModelProperty("近45日是否有开票记录") private Boolean anyPre45daysFpRcd; @ApiModelProperty("近一个月开票金额(元)") private BigDecimal hjjeZc1; @ApiModelProperty("近3个月开票环比增长率") private BigDecimal avgMonJshjYxMomRate3; @ApiModelProperty("近3个月开票金额(元)") private BigDecimal hjjeZc3; @ApiModelProperty("近6个月开票环比增长率") private BigDecimal avgMonJshjYxMomRate6; @ApiModelProperty("近6个月开票金额(元)") private BigDecimal hjjeZc6; @ApiModelProperty("近12个月开票环比增长率") private BigDecimal avgMonJshjYxMomRate12; @ApiModelProperty("近12个月开票金额(元)") private BigDecimal hjjeZc12; @ApiModelProperty("近24个月开票金额(元)") private BigDecimal hjjeZc24; @ApiModelProperty("近3个月下游客户统计") private Integer downCusCnt3; @ApiModelProperty("近12月下游客户数量(家)") private Integer downCusCnt12; @ApiModelProperty("近12个月下游开票张数") private Integer kpslQb; @ApiModelProperty("近12月作废发票数量占比") private BigDecimal kpslFpRatio; @ApiModelProperty("近12月月均开票金额增长率") private BigDecimal avgMonJshjYxYoyRate; @ApiModelProperty("近12月红冲发票张数占比") private BigDecimal kpslHpRatio; @ApiModelProperty("近12个月红冲金额占比") private BigDecimal hjjeHpRatio; @ApiModelProperty("近12个月最大连续未开票间隔天数(销项)") private Integer nokpslYxMaxdayCnt; //todo 近12个月最长连续断票月数 //todo 近12个月断票月数(不含2月份) @ApiModelProperty("近三年开票信息报表(元)") private List<Object> f4yPer1mDownFpInfoList; } ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/LicencePageVO.java
@@ -3,8 +3,11 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data public class LicencePageVO { @ApiModelProperty(value = "主键ID") ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/OrderDetailVO.java
@@ -21,7 +21,7 @@ @ApiModelProperty(value = "公司主键ID") private String id; @ApiModelProperty(value = "订单状态:1-待交易 2待确认(预订) 3已确认(待支付) 4办理中 5-已完成 6-已下架 ") @ApiModelProperty(value = "订单状态: 2待确认(预订) 3已确认(待支付) 4办理中 5-卖家已完成 6-卖家已完成 7-已下架 ") private Integer status; ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/OrderPageVO.java
@@ -43,7 +43,7 @@ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime bookTime; @ApiModelProperty(value = "订单状态:1-待交易 2待确认(预订) 3已确认(待支付) 4办理中 5-已完成 6-已下架 ") @ApiModelProperty(value = "订单状态:-1-已取消 1-待交易 2待确认(预订) 3已确认(待支付) 4办理中 6-已完成 7-已下架 ") private Integer status; @ApiModelProperty(value = "完成时间") ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/QuestionPageVO.java
@@ -11,7 +11,7 @@ @ApiModelProperty("主键ID") private Integer id; @ApiModelProperty("问题标题") private String name; private String title; @ApiModelProperty("排序") private Integer orderNum; ruoyi-system/src/main/java/com/ruoyi/system/pojo/vo/TaxVO.java
@@ -1,9 +1,66 @@ package com.ruoyi.system.pojo.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data @ApiModel("企业纳税信息") public class TaxVO { @ApiModelProperty("纳税信用等级") private String taxCreditRating; @ApiModelProperty("纳税人种类") private String taxpayerType; @ApiModelProperty("近12月增税销售额") private BigDecimal vatTaxShouldsaleAmt12; @ApiModelProperty("近24月增税销售额") private BigDecimal vatTaxShouldsaleAmt24; @ApiModelProperty("近12月纳税总额(元)") private BigDecimal taxAmt12; @ApiModelProperty("近24月纳税总额(元)") private BigDecimal taxAmt24; @ApiModelProperty("近12月增税应纳额(元)") private BigDecimal vatTaxShouldpay; @ApiModelProperty("近3月滞纳金次数") private Integer overdueFineInfoCnt3; @ApiModelProperty("近12个月滞纳金金额(元)") private BigDecimal overdueFineInfoAmt12; @ApiModelProperty("近12月滞纳金次数") private Integer overdueFineInfoCnt12; @ApiModelProperty("近12月0申报月数(月)") private Integer vatTax0dclrMonCnt; // todo 近12月0申报月数(月) // todo 当前欠税余额(元) // todo 近12月最长连续0纳税申报月数 //todo 资产金额(去年年报) //todo 负债率(去年年报) //todo 营业利润额(去年年报) //todo 营业净利率(去年年报) @ApiModelProperty("滞纳金情况") private List<Object> overdueFineDetailsList; @ApiModelProperty("近四年纳税信息完税表") private List<Object> taxPrev4yearsTaxInfoDict; @ApiModelProperty("税务处罚") private Object enterprise; } ruoyi-system/src/main/java/com/ruoyi/system/service/OrderService.java
@@ -3,13 +3,13 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.utils.wx.RefundCallbackResult; import com.ruoyi.system.domain.Agreement; import com.ruoyi.system.domain.Order; import com.ruoyi.system.pojo.dto.AddAgreementDTO; import com.ruoyi.system.pojo.dto.FinanceFlowsDTO; import com.ruoyi.system.pojo.dto.OrderPageDTO; import com.ruoyi.system.pojo.dto.WithdrawPageDTO; import com.ruoyi.system.pojo.vo.*; import java.time.LocalDate; @@ -23,13 +23,13 @@ BusinessVO business(String id); ErrorVO error(String id); R error(String id); ChangeVO change(String id); R change(String id); TaxVO tax(String id); R tax(String id); InvoiceVO invoice(String id); R invoice(String id); void delete(String id); @@ -37,13 +37,13 @@ void cancel(String id); R refundPayMoneyCallback(RefundCallbackResult refundCallbackResult); R refundPayMoneyCallback(String xmlData); TodayStatisticsVO today(); IndexLineChartVO chart(LocalDate startDate, LocalDate endDate); FinanceFlowsTopVO financeTop(); FinanceFlowsTopVO financeTop(FinanceFlowsDTO dto); IPage<FinanceFlowsPageVO> flowsPage(FinanceFlowsDTO dto); ruoyi-system/src/main/java/com/ruoyi/system/service/QuestionService.java
@@ -15,7 +15,7 @@ public interface QuestionService extends IService<Question> { IPage<QuestionPageVO> getQuestionPage(Integer pageNum, Integer pageSize, String name); IPage<QuestionPageVO> getQuestionPage(Integer pageNum, Integer pageSize, String title); void add(AddQuestionDTO dto); ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AppUserServiceImpl.java
@@ -62,9 +62,12 @@ //2.2计算订单金额 扣减超时订单金额 for(BuyerInfoAndOrder order :orders) { BigDecimal total = new BigDecimal("0.00"); order.setPrice(order.getPrice()==null?BigDecimal.ZERO:order.getPrice()); order.setCommissionPrice(order.getCommissionPrice()==null?BigDecimal.ZERO:order.getCommissionPrice()); order.setCommissionPlatform(order.getCommissionPlatform()==null?BigDecimal.ZERO:order.getCommissionPlatform()); total = total.add(order.getPrice()).subtract(order.getCommissionPrice()).subtract(order.getCommissionPlatform()); System.out.println(total); //扣减超时订单 /*//扣减超时订单 //到期时间 支付时间 + 预计时间 + 新增时间 LocalDateTime end = order.getPayTime().plusDays(order.getEstimatedDays()).plusDays(order.getAddDay()); LocalDateTime now = LocalDateTime.now();//计算扣费时间 @@ -78,7 +81,7 @@ long days= (seconds + 86399) / 86400;//24小时 //计算天数差 BigDecimal dailyAmount = new BigDecimal("100.00"); total = total.subtract((dailyAmount.multiply(BigDecimal.valueOf(days)))); total = total.subtract((dailyAmount.multiply(BigDecimal.valueOf(days))));*/ recorded = recorded.add(total); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LicenceServiceImpl.java
@@ -27,10 +27,11 @@ public void add(AddLicenceDTO dto) { //判断是否存在 Licence licence = this.baseMapper.selectOne(new LambdaQueryWrapper<Licence>().eq(Licence::getName, dto.getName()).eq(Licence::getDelFlag, 0)); if (null == licence) { if (null != licence) { throw new ServiceException("许可证名称重复"); } licence = new Licence(); BeanUtils.copyProperties(dto, licence); String grand = String.join(";", dto.getGrandNameList());//多个以分号相隔 licence.setGradeName(grand); ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderServiceImpl.java
@@ -1,29 +1,32 @@ package com.ruoyi.system.service.impl; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.wx.PaymentUtil; import com.ruoyi.common.utils.wx.RefundCallbackResult; import com.ruoyi.common.utils.wx.RefundResult; import com.ruoyi.system.domain.*; import com.ruoyi.system.mapper.*; import com.ruoyi.system.pojo.dto.AddAgreementDTO; import com.ruoyi.system.pojo.dto.FinanceFlowsDTO; import com.ruoyi.system.pojo.dto.OrderPageDTO; import com.ruoyi.system.pojo.dto.WithdrawPageDTO; import com.ruoyi.system.pojo.model.DailyStatistics; import com.ruoyi.system.pojo.model.DrawSheet; import com.ruoyi.system.pojo.vo.*; import com.ruoyi.system.service.AgreementService; import com.ruoyi.system.service.OrderService; import com.ruoyi.system.wx.RefundCallbackResult; import com.ruoyi.system.wx.WechatPayService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.provisioning.UserDetailsManager; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,9 +35,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.*; import java.util.concurrent.TimeUnit; @Slf4j @Service @@ -53,12 +55,15 @@ private ScheduleMapper scheduleMapper; @Resource private CompanyMapper companyMapper; @Autowired private SystemConfigMapper systemConfigMapper; @Autowired private AppUserMapper appUserMapper; @Autowired private WithdrawMapper withdrawMapper; @Resource private RedisCache redisCache; @Resource private QichachaMapper qichachaMapper; @Override public IPage<OrderPageVO> getOrderPage(OrderPageDTO dto) { @@ -77,8 +82,11 @@ List<PermitVO> permitVOs = new ArrayList<>(); LocalDateTime now = LocalDateTime.now(); for (Permit permit : permits) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime expireTime = LocalDateTime.parse(permit.getExpireTime(), formatter); DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate expireDate = LocalDate.parse(permit.getExpireTime(), dateFormatter); // 如果需要转为 LocalDateTime(添加默认时间) LocalDateTime expireTime = expireDate.atTime(23,59,59); // 默认00:00:00 if (now.isAfter(expireTime)) { //过滤 未过期的 PermitVO permitVO = new PermitVO(); @@ -98,7 +106,7 @@ } vo.setOpeningBankVOList(openingBankVOs); if (vo.getStatus() != 4 && vo.getStatus() != 5) { if (vo.getStatus() != 4 && vo.getStatus() != 5&& vo.getStatus() != 6) { return vo; } @@ -146,6 +154,7 @@ @Override public BusinessVO business(String id) { //先查询数据库中的 Company company = companyMapper.selectById(id); if (null == company || company.getIsDelete() != 0) { throw new ServiceException("公司不存在"); @@ -153,29 +162,347 @@ BusinessVO vo = new BusinessVO(); BeanUtils.copyProperties(company, vo); vo.setPlace(company.getCity()+company.getProvince()+company.getArea()); //todo 再查企业工商信息 覆盖掉之前的 return vo; } @Override public ErrorVO error(String id) { return null; public R error(String id) { ErrorVO errorVO = new ErrorVO(); Company company = companyMapper.selectById(id); if (null == company || company.getIsDelete() != 0) { throw new ServiceException("公司不存在"); } JSONObject result = getQiChaChaCompanyExceptionCheck(company.getCompanyName()); if("200".equals(result.get("Status"))){ //查询成功 JSONObject data = (JSONObject) result.get("Result"); Integer verifyResult = (Integer) data.get("VerifyResult"); errorVO.setVerifyResult(verifyResult); if (verifyResult==1){ //该企业有异常数据 JSONArray list = (JSONArray) data.get("Data"); errorVO.setData(list); } return R.ok(errorVO); }else { //查询失败 return R.fail(result.get("Message")); } } /** * 经营异常核查 * @param companyName * @return * VerifyResult int 数据是否存在(1-存在,0-不存在) * Data List<Object> 数据信息 * Data:[{ * AddReason 列入经营异常名录原因 * AddDate 列入日期 * RomoveReason 移出经营异常名录原因(保留字段) * RemoveDate 移出日期(保留字段) * DecisionOffice 作出决定机关 * RemoveDecisionOffice 移出决定机关(保留字段) * }] * Status * Message * OrderNumber */ public JSONObject getQiChaChaBasicDetailsCompany(String companyName){ Object cacheObject = redisCache.getCacheObject("qichacha_" +"basic_"+ companyName); if(cacheObject != null){ JSONObject jsonObject = JSONObject.parseObject(cacheObject.toString()); return jsonObject; } String url = "https://api.qichacha.com/ECIV4/GetBasicDetailsByName?key=642987ca3faf4a7daeac70463ae22695&keyword="+companyName; HttpRequest get = HttpUtil.createGet(url); String timeStr = String.valueOf(System.currentTimeMillis() / 1000); get.header("Token", SecureUtil.md5("642987ca3faf4a7daeac70463ae22695"+timeStr+"AC776F2957291EAE3B4161702E89A9F3").toUpperCase()); get.header("Timespan", timeStr); HttpResponse execute = get.execute(); String body = execute.body(); JSONObject jsonObject = JSONObject.parseObject(body); if("200".equals(jsonObject.get("Status"))){ //查询成功 String string = jsonObject.toString(); redisCache.setCacheObject("qichacha_"+"basic_"+companyName,string,24, TimeUnit.HOURS); //统计调用次数 Qichacha qichacha = new Qichacha(); qichacha.setTime(LocalDateTime.now()); qichacha.setType(1);//企业异常查询 qichachaMapper.insert(qichacha); return jsonObject; } return jsonObject; } /** * 经营异常核查 * @param companyName * @return * VerifyResult int 数据是否存在(1-存在,0-不存在) * Data List<Object> 数据信息 * Data:[{ * AddReason 列入经营异常名录原因 * AddDate 列入日期 * RomoveReason 移出经营异常名录原因(保留字段) * RemoveDate 移出日期(保留字段) * DecisionOffice 作出决定机关 * RemoveDecisionOffice 移出决定机关(保留字段) * }] * Status * Message * OrderNumber */ public JSONObject getQiChaChaCompanyExceptionCheck(String companyName){ Object cacheObject = redisCache.getCacheObject("qichacha_" + companyName); if(cacheObject != null){ JSONObject jsonObject = JSONObject.parseObject(cacheObject.toString()); return jsonObject; } String url = "https://api.qichacha.com/ExceptionCheck/GetList?key=642987ca3faf4a7daeac70463ae22695&searchKey="+companyName; HttpRequest get = HttpUtil.createGet(url); String timeStr = String.valueOf(System.currentTimeMillis() / 1000); get.header("Token", SecureUtil.md5("642987ca3faf4a7daeac70463ae22695"+timeStr+"AC776F2957291EAE3B4161702E89A9F3").toUpperCase()); get.header("Timespan", timeStr); HttpResponse execute = get.execute(); String body = execute.body(); JSONObject jsonObject = JSONObject.parseObject(body); if("200".equals(jsonObject.get("Status"))){ //查询成功 String string = jsonObject.toString(); redisCache.setCacheObject("qichacha_"+companyName,string,24, TimeUnit.HOURS); //统计调用次数 Qichacha qichacha = new Qichacha(); qichacha.setTime(LocalDateTime.now()); qichacha.setType(2);//企业异常查询 qichachaMapper.insert(qichacha); return jsonObject; } return jsonObject; } private JSONObject getReport(String sign){ Object cacheObject = redisCache.getCacheObject("shuimu_" + sign); if(cacheObject != null){ JSONObject jsonObject = JSONObject.parseObject(cacheObject.toString()); return jsonObject; } HttpRequest post = HttpUtil.createPost("https://shuimui.szsmjr.com/index/index/result"); HashMap<String, String> stringStringHashMap = new HashMap<>(); stringStringHashMap.put("Origin","https://shuimui.szsmjr.com"); post.addHeaders(stringStringHashMap); post.body("{\"sn\":\""+sign+"\"}"); HttpResponse execute = post.execute(); String body = execute.body(); JSONObject jsonObject = JSONObject.parseObject(body); if("1001".equals(jsonObject.get("code"))){ //查询成功 String string = jsonObject.toString(); redisCache.setCacheObject("shuimu_"+sign,string,1, TimeUnit.MINUTES); return jsonObject; } return jsonObject; } @Override public R change(String id) { // System.err.println(getReport("ZZD20250508017232394218445")); ChangeVO changeVO = new ChangeVO(); /* Company companyInfo = companyMapper.selectById(id); if (null == companyInfo || companyInfo.getIsDelete() != 0) { throw new ServiceException("公司不存在"); }*/ // JSONObject jsonObject=getReport(companyInfo.getLink().split("=")[1]); JSONObject jsonObject=getReport("ZZD20250508017232394218445"); if (!"1001".equals(jsonObject.getString("code"))){ return R.fail(jsonObject.get("msg")); } JSONObject data1 = (JSONObject) jsonObject.get("data"); JSONObject data2 = (JSONObject) data1.get("data"); JSONObject company = (JSONObject) data2.get("company"); // 银税互动 JSONArray bankAndTaxInteractive = (JSONArray) company.get("bankAndTaxInteractive"); changeVO.setBankAndTaxInteractive(bankAndTaxInteractive); //股东明细 JSONArray sharesRatioList = (JSONArray) company.get("sharesRatioList"); changeVO.setSharesRatioList(sharesRatioList); //法人/股东变更 JSONArray legalPersonGdChange = (JSONArray) company.get("legalPersonGdChange"); changeVO.setLegalPersonGdChange(legalPersonGdChange); return R.ok(changeVO); } @Override public ChangeVO change(String id) { return null; public R tax(String id) { TaxVO taxVO = new TaxVO(); /* Company companyInfo = companyMapper.selectById(id); if (null == companyInfo || companyInfo.getIsDelete() != 0) { throw new ServiceException("公司不存在"); }*/ // JSONObject jsonObject=getReport(companyInfo.getLink().split("=")[1]); JSONObject jsonObject=getReport("ZZD20250508017232394218445"); if (!"1001".equals(jsonObject.getString("code"))){ return R.fail(jsonObject.get("msg")); } JSONObject data1 = (JSONObject) jsonObject.get("data"); JSONObject data2 = (JSONObject) data1.get("data"); JSONObject taxInfo = (JSONObject) data2.get("taxInfo"); //税务处罚 JSONObject enterprise = (JSONObject) data2.get("enterprise"); taxVO.setEnterprise(enterprise); //滞纳金情况 JSONArray overdueFineDetailsList = (JSONArray) taxInfo.get("overdueFineDetailsList"); taxVO.setOverdueFineDetailsList(overdueFineDetailsList); //近四年纳税信息完税表 JSONArray taxPrev4yearsTaxInfoDict = (JSONArray) taxInfo.get("taxPrev4yearsTaxInfoDict"); taxVO.setTaxPrev4yearsTaxInfoDict(taxPrev4yearsTaxInfoDict); //纳税信用等级 String taxCreditRating = (String) taxInfo.get("taxCreditRating"); taxVO.setTaxCreditRating(taxCreditRating); //纳税人种类 String taxpayerType = (String) taxInfo.get("taxpayerType"); taxVO.setTaxpayerType(taxpayerType); //近12月增税销售额 JSONObject taxPrevMnMthsAllTaxDclrPrjInfoDict = (JSONObject) taxInfo.get("taxPrevMnMthsAllTaxDclrPrjInfoDict"); JSONObject taxPrev12mthsAllTaxDclrPrjInfoDict = (JSONObject) taxPrevMnMthsAllTaxDclrPrjInfoDict.get("taxPrev12mthsAllTaxDclrPrjInfoDict"); taxVO.setVatTaxShouldsaleAmt12((BigDecimal) taxPrev12mthsAllTaxDclrPrjInfoDict.get("vatTaxShouldsaleAmt")); //近24月增税销售额 JSONObject taxPrev24mthsAllTaxDclrPrjInfoDict = (JSONObject) taxPrevMnMthsAllTaxDclrPrjInfoDict.get("taxPrev24mthsAllTaxDclrPrjInfoDict"); taxVO.setVatTaxShouldsaleAmt24( (BigDecimal) taxPrev24mthsAllTaxDclrPrjInfoDict.get("vatTaxShouldsaleAmt")); JSONObject taxPrevMnMthsTaxInfoDict = (JSONObject) taxInfo.get("taxPrevMnMthsTaxInfoDict"); //近12月纳税总额(元) JSONObject taxPrev12mthsTaxInfo = (JSONObject) taxPrevMnMthsTaxInfoDict.get("taxPrev12mthsTaxInfo"); taxVO.setTaxAmt12( (BigDecimal) taxPrev12mthsTaxInfo.get("taxAmt")); //近24月纳税总额(元) JSONObject taxPrev24mthsTaxInfo = (JSONObject) taxPrevMnMthsTaxInfoDict.get("taxPrev24mthsTaxInfo"); taxVO.setTaxAmt24( (BigDecimal) taxPrev24mthsTaxInfo.get("taxAmt")); //近12月增税应纳额(元) taxVO.setVatTaxShouldpay( (BigDecimal) taxPrev12mthsAllTaxDclrPrjInfoDict.get("vatTaxShouldpay")); //近12个月滞纳金金额(元) 次数 JSONObject taxPrevMnMthsOverdueFineInfoDict = (JSONObject) taxInfo.get("taxPrevMnMthsOverdueFineInfoDict"); JSONObject taxPrev12mthsOverdueFineInfo = (JSONObject) taxPrevMnMthsOverdueFineInfoDict.get("taxPrev12mthsOverdueFineInfo"); taxVO.setOverdueFineInfoAmt12( (BigDecimal) taxPrev12mthsOverdueFineInfo.get("overdueFineInfoAmt")); taxVO.setOverdueFineInfoCnt12( (Integer) taxPrev12mthsOverdueFineInfo.get("overdueFineInfoCnt")); // 近3个月滞纳金金额(元) JSONObject taxPrev3mthsOverdueFineInfo = (JSONObject) taxPrevMnMthsOverdueFineInfoDict.get("taxPrev3mthsOverdueFineInfo"); taxVO.setOverdueFineInfoCnt3( (Integer) taxPrev3mthsOverdueFineInfo.get("overdueFineInfoCnt")); //近12月0申报月数(月数) JSONObject taxPrevMnMthsAllTaxDclrInfoDict = (JSONObject) taxInfo.get("taxPrevMnMthsAllTaxDclrInfoDict"); JSONObject taxPrev12mthsAllTaxDclrInfoDict = (JSONObject) taxPrevMnMthsAllTaxDclrInfoDict.get("taxPrev12mthsAllTaxDclrInfoDict"); taxVO.setVatTax0dclrMonCnt( (Integer) taxPrev12mthsAllTaxDclrInfoDict.get("vatTax0dclrMonCnt")); return R.ok(taxVO); } @Override public TaxVO tax(String id) { return null; public R invoice(String id) { InvoiceVO vo = new InvoiceVO(); /* Company companyInfo = companyMapper.selectById(id); if (null == companyInfo || companyInfo.getIsDelete() != 0) { throw new ServiceException("公司不存在"); }*/ // JSONObject jsonObject=getReport(companyInfo.getLink().split("=")[1]); JSONObject jsonObject=getReport("ZZD20250508017232394218445"); if (!"1001".equals(jsonObject.getString("code"))){ return R.fail(jsonObject.get("msg")); } JSONObject data1 = (JSONObject) jsonObject.get("data"); JSONObject data2 = (JSONObject) data1.get("data"); JSONObject invoiceInfo = (JSONObject) data2.get("invoiceInfo"); //近45日是否有开票记录 vo.setAnyPre45daysFpRcd((Boolean) invoiceInfo.get("anyPre45daysFpRcd")); //近一个月开票金额(元) JSONArray f4yPer1mDownFpInfoList = (JSONArray) invoiceInfo.get("f4yPer1mDownFpInfoList"); JSONObject f4yPer1mDownFpInfo1 = (JSONObject) f4yPer1mDownFpInfoList.get(1); vo.setHjjeZc1( ObjectToBigDecimal(f4yPer1mDownFpInfo1.get("hjjeZc")) ); JSONObject fpPrevMnMthsDownFpInfoList = (JSONObject) invoiceInfo.get("fpPrevMnMthsDownFpInfoList"); JSONObject fpPrev3mthsDownFpInfoList = (JSONObject) fpPrevMnMthsDownFpInfoList.get("fpPrev3mthsDownFpInfoList"); //近3个月开票环比增长率 vo.setAvgMonJshjYxMomRate3( ObjectToBigDecimal(fpPrev3mthsDownFpInfoList.get("avgMonJshjYxMomRate")) ); //近3个月开票金额(元) vo.setHjjeZc3( ObjectToBigDecimal( fpPrev3mthsDownFpInfoList.get("hjjeZc") )); JSONObject fpPrev6mthsDownFpInfoList = (JSONObject) fpPrevMnMthsDownFpInfoList.get("fpPrev6mthsDownFpInfoList"); //近6个月开票环比增长率 vo.setAvgMonJshjYxMomRate6( ObjectToBigDecimal(fpPrev6mthsDownFpInfoList.get("avgMonJshjYxMomRate")) ); //近6月开票金额(元) vo.setHjjeZc6( ObjectToBigDecimal(fpPrev6mthsDownFpInfoList.get("hjjeZc")) ); JSONObject fpPrev12mthsDownFpInfoList = (JSONObject) fpPrevMnMthsDownFpInfoList.get("fpPrev12mthsDownFpInfoList"); //近12个月开票环比增长率 vo.setAvgMonJshjYxMomRate12( ObjectToBigDecimal(fpPrev12mthsDownFpInfoList.get("avgMonJshjYxMomRate")) ); //近12月开票金额(元) vo.setHjjeZc12( ObjectToBigDecimal(fpPrev12mthsDownFpInfoList.get("hjjeZc")) ); //近24个月开票金额(元) JSONObject fpPrev24mthsDownFpInfoList = (JSONObject) fpPrevMnMthsDownFpInfoList.get("fpPrev24mthsDownFpInfoList"); vo.setHjjeZc24( ObjectToBigDecimal(fpPrev24mthsDownFpInfoList.get("hjjeZc") )); //近12个月下游客户统计 vo.setDownCusCnt3( (Integer) fpPrev3mthsDownFpInfoList.get("downCusCnt")); //近12个月下游客户统计 vo.setDownCusCnt12( (Integer) fpPrev12mthsDownFpInfoList.get("downCusCnt")); //近12个月下游开票张数 vo.setKpslQb( (Integer) fpPrev12mthsDownFpInfoList.get("kpslQb")); //近12月作废发票数量占比 vo.setKpslFpRatio(ObjectToBigDecimal(fpPrev12mthsDownFpInfoList.get("kpslFpRatio"))); //近12月月均开票金额增长率 vo.setAvgMonJshjYxYoyRate(ObjectToBigDecimal(fpPrev12mthsDownFpInfoList.get("avgMonJshjYxYoyRate")) ); //近12月红冲发票张数占比 vo.setKpslHpRatio(ObjectToBigDecimal(fpPrev12mthsDownFpInfoList.get("kpslHpRatio"))); //近12个月红冲金额占比 vo.setHjjeHpRatio(ObjectToBigDecimal(fpPrev12mthsDownFpInfoList.get("hjjeHpRatio")) ); //近12个月最大连续未开票间隔天数(销项) vo.setNokpslYxMaxdayCnt((Integer) fpPrev12mthsDownFpInfoList.get("nokpslYxMaxdayCnt")); //近三年开票信息报表(元) vo.setF4yPer1mDownFpInfoList(f4yPer1mDownFpInfoList); return R.ok(vo); } @Override public InvoiceVO invoice(String id) { return null; } private BigDecimal ObjectToBigDecimal(Object o) { // 处理不同类型的情况 if ( o instanceof BigDecimal) { return (BigDecimal) o; } else if (o instanceof Number) { // 将其他数字类型(如 Integer、Double)转换为 BigDecimal return BigDecimal.valueOf(((Number) o).doubleValue()); } return BigDecimal.ZERO; } @Transactional @Override public void delete(String id) { @@ -191,6 +518,7 @@ //查看订单状态是否为待确认 Order order = this.baseMapper.selectOne(new LambdaQueryWrapper<Order>() .eq(Order::getCompanyId, company.getId()) .eq(Order::getIsRefund,0) .ne(Order::getStatus,-1));//取消的订单不要 if (null == order) { throw new ServiceException("订单不存在"); @@ -254,7 +582,7 @@ if (!company.getStatus().equals(4)){// 4-锁定中 throw new ServiceException("订单状态错误,不能操作"); } //查看订单 取消的不要 //查看订单 Order order = this.baseMapper.selectOne(new LambdaQueryWrapper<Order>() .eq(Order::getCompanyId, company.getId()) .ne(Order::getStatus,-1)); @@ -262,10 +590,10 @@ throw new ServiceException("订单不存在"); } //检查状态 3已确认(未付款) 4办理中 5卖家已完成 if (!order.getStatus().equals(3)||!order.getStatus().equals(4)||!order.getStatus().equals(5)) { if (!order.getStatus().equals(3)&&!order.getStatus().equals(4)&&!order.getStatus().equals(5)) { throw new ServiceException("订单状态错误,不能操作"); } if (company.getStatus().equals(3)){ if (order.getStatus().equals(3)){ //未付款 直接取消订单 order.setStatus(-1); this.baseMapper.updateById(order); @@ -275,52 +603,91 @@ appUserMapper.updateById(user); //商品状态修改 company.setStatus(1); order.setIsRefund(1); order.setRefundTime(LocalDateTime.now()); companyMapper.updateById(company); }else{ R r = refundPayMoney(order);//退款 if (200 == r.getCode()) { //退款成功 order.setStatus(-1);//订单取消状态 order.setIsRefund(1);//退款标志 order.setRefundTime(LocalDateTime.now());//退款时间 this.updateById(order); //将分佣次数加回 User user = appUserMapper.selectById(order.getUserId()); user.setInviteNum(user.getInviteNum()+1); appUserMapper.updateById(user); //商品状态修改 company.setStatus(1); companyMapper.updateById(company); //退款申请成功 log.info("退款申请成功,订单id:{}",order.getId()); } } } @Override public R refundPayMoneyCallback(RefundCallbackResult refundCallbackResult) { String code = refundCallbackResult.getR3_RefundOrderNo().substring(1); log.info("退款回调:{}",code); Order order = this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, code)); public R refundPayMoneyCallback(String xmlData ) { RefundCallbackResult result = wechatPayService.processRefundCallback(xmlData); if (!result.isSuccess()) { System.out.println("会员退费错误:"+result.getMsg()); return R.fail(result.getMsg()); } Order order = this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, result.getOrderNo())); if (null == order || order.getStatus() == -1) { return R.ok(); } order.setStatus(-1); order.setIsRefund(1); order.setRefundTime(LocalDateTime.now()); this.updateById(order); //查找公司 Company company = companyMapper.selectById(order.getCompanyId()); //取消订单 order.setStatus(-1); order.setIsRefund(1); order.setRefundTime(LocalDateTime.now()); this.baseMapper.updateById(order); //将分佣次数加回 User user = appUserMapper.selectById(order.getUserId()); User inviter = appUserMapper.selectById(user.getInviteId()); if (inviter!=null && inviter.getIsDelete()==0){ inviter.setInviteNum(inviter.getInviteNum()+1); appUserMapper.updateById(inviter); } //商品状态修改 company.setStatus(1); companyMapper.updateById(company); return R.ok(); } /** * 返回订单支付金额 */ @Autowired private WechatPayService wechatPayService; @Transactional public R refundPayMoney(Order order) { //开始退款 BigDecimal paymentAmount = order.getPrice(); if (BigDecimal.ZERO.compareTo(order.getPrice()) < 0) {//支付的金额是否大于0 //微信退款 RefundResult refund = PaymentUtil.refund(order.getOrderNo(), "R" + order.getOrderNo(), paymentAmount.doubleValue(), "/system/order/refundPayMoneyCallback"); if (!"100".equals(refund.getRa_Status())) { return R.fail(refund.getRc_CodeMsg());//退款失败 Map<String,String> map = wechatPayService.refund(order.getOrderNo(), order.getOrderNo(), order.getPrice().toString(), order.getPrice().toString(), "平台取消订单", "/system/order/refundPayMoneyCallback"); if (!"SUCCESS".equals(map.get("return_code"))) { return R.fail(map.get("return_msg"));//退款失败 } } //查找公司 Company company = companyMapper.selectById(order.getCompanyId()); //取消订单 order.setStatus(-1); order.setIsRefund(1); order.setRefundTime(LocalDateTime.now()); this.baseMapper.updateById(order); //将分佣次数加回 User user = appUserMapper.selectById(order.getUserId()); User inviter = appUserMapper.selectById(user.getInviteId()); if (inviter!=null && inviter.getIsDelete()==0){ inviter.setInviteNum(inviter.getInviteNum()+1); appUserMapper.updateById(inviter); } //商品状态修改 company.setStatus(1); companyMapper.updateById(company); return R.ok(); } @@ -369,14 +736,16 @@ } @Override public FinanceFlowsTopVO financeTop() { return this.baseMapper.financeTop(); public FinanceFlowsTopVO financeTop(FinanceFlowsDTO dto) { return this.baseMapper.financeTop(dto); } @Override public IPage<FinanceFlowsPageVO> flowsPage(FinanceFlowsDTO dto) { IPage<FinanceFlowsPageVO> page = new Page<>(dto.getPageNum(), dto.getPageSize()); Long total = this.baseMapper.countFlowsPage(dto); //分页处理 dto.setOffset((dto.getPageNum()-1)*dto.getPageSize()); IPage<FinanceFlowsPageVO> financeFlowsPageVOIPage = this.baseMapper.flowsPage(page, dto); financeFlowsPageVOIPage.setTotal(total); return financeFlowsPageVOIPage; ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QuestionServiceImpl.java
@@ -20,9 +20,9 @@ @Override public IPage<QuestionPageVO> getQuestionPage(Integer pageNum, Integer pageSize, String name) { public IPage<QuestionPageVO> getQuestionPage(Integer pageNum, Integer pageSize, String title) { IPage<BannerPageVO> page=new Page<>(pageNum, pageSize); return this.baseMapper.getQuestionPage(page,name); return this.baseMapper.getQuestionPage(page,title); } @Override ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -480,14 +480,21 @@ //判断角色名称是否存在 SysRole sysRole = new SysRole(); sysRole.setRoleName(dto.getRoleName()); List<SysRole> sysRoles = roleMapper.selectRoleList(sysRole); if (sysRoles!=null && !sysRoles.isEmpty()){ throw new ServiceException("该角色名称重复"); sysRoles.forEach(role -> { if (!role.getRoleId().equals(dto.getRoleId())){ throw new ServiceException("该角色名称重复"); } }); } //删除之前的 //删除之前的角色菜单关联 roleMenuMapper.deleteRoleMenuByRoleId(dto.getRoleId()); //修改角色名称 roleMapper.updateRole(sysRole); //添加角色菜单 roleMenuMapper.insert(sysRole.getRoleId(),dto.getMenuIds()); roleMenuMapper.insert(dto.getRoleId(),dto.getMenuIds()); } @Override ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -1,6 +1,7 @@ package com.ruoyi.system.service.impl; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -565,7 +566,7 @@ @Override public R<SysUserVO> getInfo(Long userId) { return userMapper.getSysUserVO(userId); return R.ok(userMapper.getSysUserVO(userId)); } @Override @@ -591,7 +592,7 @@ sysUser.setPhonenumber(dto.getPhonenumber()); sysUser.setNickName(dto.getNickName()); //后六位为默认密码 sysUser.setPassword(SecurityUtils.encryptPassword(Md5Utils.hash(dto.getPhonenumber().substring(6,12)))); sysUser.setPassword(SecurityUtils.encryptPassword(Md5Utils.hash(dto.getPhonenumber().substring(5,11)))); sysUser.setStatus("0"); sysUser.setDeptId(dto.getDeptId()); //添加用户-部门关系 userMapper.insertUser(sysUser); @@ -662,7 +663,7 @@ if (sysUser==null){ throw new ServiceException("该用户不存在"); } sysUser.setPassword(SecurityUtils.encryptPassword(Md5Utils.hash(sysUser.getPassword().substring(6,12)))); sysUser.setPassword(SecurityUtils.encryptPassword(Md5Utils.hash(sysUser.getPhonenumber().substring(5,11)))); userMapper.updateUser(sysUser); } } ruoyi-system/src/main/java/com/ruoyi/system/wx/HttpUtil.java
New file @@ -0,0 +1,99 @@ package com.ruoyi.system.wx; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import javax.net.ssl.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; /** * HTTP工具类 */ public class HttpUtil { /** * 发送POST请求 */ public static String post(String urlStr, String data) throws Exception { // 设置超时时间(单位:毫秒) int timeout = 5000; // 5秒 // 发送 POST 请求 try (HttpResponse response = HttpRequest.post(urlStr) .body(data, "application/xml") // 设置 XML 请求体 .timeout(timeout) .execute()) { // 检查 HTTP 状态码 if (!response.isOk()) { throw new RuntimeException("HTTP请求失败,状态码: " + response.getStatus() + ", 响应: " + response.body()); } return response.body(); } } /** * 发送HTTPS请求 */ public static String postHttps(String urlStr, String data, String certPath, String certPassword) throws Exception { // 创建SSL上下文 SSLContext sslContext = SSLContext.getInstance("SSL"); TrustManager[] trustManagers = {new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }}; sslContext.init(null, trustManagers, new java.security.SecureRandom()); // 创建HTTPS连接 URL url = new URL(urlStr); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(sslContext.getSocketFactory()); conn.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestProperty("Content-Type", "application/xml"); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Charset", "UTF-8"); // 发送请求 OutputStream os = conn.getOutputStream(); os.write(data.getBytes("UTF-8")); os.flush(); os.close(); // 获取响应 StringBuilder result = new StringBuilder(); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = br.readLine()) != null) { result.append(line); } br.close(); return result.toString(); } } ruoyi-system/src/main/java/com/ruoyi/system/wx/MD5AndKL.java
File was renamed from ruoyi-common/src/main/java/com/ruoyi/common/utils/wx/MD5AndKL.java @@ -1,4 +1,4 @@ package com.ruoyi.common.utils.wx; package com.ruoyi.system.wx; import java.security.MessageDigest; ruoyi-system/src/main/java/com/ruoyi/system/wx/PayResult.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.wx; import lombok.Data; /** * 支付结果VO */ @Data public class PayResult { // 订单ID private String orderNumber; // 微信交易ID private String transactionId; // 支付金额 private String totalFee; } ruoyi-system/src/main/java/com/ruoyi/system/wx/RefundCallbackResult.java
New file @@ -0,0 +1,38 @@ package com.ruoyi.system.wx; import lombok.Data; /** * 退款回调结果实体 */ @Data public class RefundCallbackResult { private boolean success; // 处理是否成功 private String msg; // 结果描述 private String orderNo; // 原订单号 private String refundNo; // 退款订单号 private String refundId; // 微信退款ID private String totalFee; // 原订单金额(分) private String refundFee; // 退款金额(分) private String refundStatus; // 退款状态 // 成功响应 public static RefundCallbackResult success() { return success("处理成功"); } public static RefundCallbackResult success(String msg) { RefundCallbackResult result = new RefundCallbackResult(); result.setSuccess(true); result.setMsg(msg); return result; } // 失败响应 public static RefundCallbackResult fail(String msg) { RefundCallbackResult result = new RefundCallbackResult(); result.setSuccess(false); result.setMsg(msg); return result; } } ruoyi-system/src/main/java/com/ruoyi/system/wx/WechatPayConfig.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.system.wx; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * 微信支付配置类 */ @Data @Component @ConfigurationProperties(prefix = "wx") public class WechatPayConfig { // 小程序APPID private String appId; // 商户号 private String mchId; // 商户API密钥 private String key; // 支付结果通知地址 private String callbackPath; // 证书路径 private String certPath; // 商户RAS加密公钥路径 private String RASPath; private String wxAppletsAppSecret; } ruoyi-system/src/main/java/com/ruoyi/system/wx/WechatPayService.java
New file @@ -0,0 +1,726 @@ package com.ruoyi.system.wx; import com.alibaba.fastjson2.JSON; import com.ruoyi.common.core.domain.R; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.dom4j.DocumentException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import sun.security.util.DerInputStream; import sun.security.util.DerValue; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.*; import java.security.spec.RSAPublicKeySpec; import java.util.*; /** * 微信支付服务类 */ @Service public class WechatPayService { @Autowired private WechatPayConfig wechatPayConfig; private static final String RSA_PUBLIC_KEY_FILENAME = "wechat_rsa_public_key.pem"; private static final String CERT_FOLDER = "cert/"; /** * 统一下单 * @param orderNumber 订单号 * @param totalFee 总金额(分) * @param body 商品描述 * @param openid 用户openid * @return 预支付订单信息 */ public R unifiedOrder(String orderId,String orderNumber, String totalFee, String body, String openid, String callbackPath) throws Exception { int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue(); String hostAddress = null; try { hostAddress = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } // 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("appid", wechatPayConfig.getAppId()); params.put("mch_id", wechatPayConfig.getMchId()); params.put("nonce_str", generateNonceStr()); params.put("body", body); params.put("out_trade_no", orderNumber); params.put("total_fee", String.valueOf(i) ); params.put("spbill_create_ip", "221.182.45.100"); // 实际应用中应获取客户端IP params.put("notify_url", wechatPayConfig.getCallbackPath()+callbackPath); params.put("trade_type", "JSAPI"); params.put("openid", openid); // 生成签名 String sign = weixinSignature(params); params.put("sign", sign); // 将参数转换为XML String xmlParams = XMLUtil.mapToXml(params).replaceFirst("^<\\?xml.+?\\?>\\s*", ""); // 发送请求到微信支付统一下单接口 String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; String result = HttpUtil.post(url, xmlParams); // 解析返回结果 Map<String, String> resultMap = XMLUtil.xmlToMap(result); // 验证签名 if (!verifySign(resultMap, wechatPayConfig.getKey())) { return R.fail("微信支付签名验证失败"); // throw new Exception("微信支付签名验证失败"); } if (!resultMap.get("return_code").equals("SUCCESS")) { return R.fail(resultMap.get("return_msg")); } // 构建小程序支付所需参数 Map<String, String> payParams = new HashMap<>(); payParams.put("appId", wechatPayConfig.getAppId()); payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); payParams.put("nonceStr", generateNonceStr()); payParams.put("package", "prepay_id=" + resultMap.get("prepay_id")); payParams.put("signType", "MD5"); // 生成支付签名 String paySign = weixinSignature(payParams); payParams.put("paySign", paySign); //给前端标识 // payParams.put("payMethod","1"); payParams.put("orderId", orderId); return R.ok(JSON.toJSONString(payParams)); } /** * 微信下单的签名算法 * @param map * @return */ private String weixinSignature(Map<String, String> map){ try { Set<Map.Entry<String, String>> entries = map.entrySet(); List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(entries); // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() { public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) { return (o1.getKey()).toString().compareTo(o2.getKey()); } }); // 构造签名键值对的格式 StringBuilder sb = new StringBuilder(); for (Map.Entry<String, String> item : infoIds) { if (item.getKey() != null || item.getKey() != "") { String key = item.getKey(); Object val = item.getValue(); if (!(val == "" || val == null)) { sb.append(key + "=" + val + "&"); } } } sb.append("key=" + wechatPayConfig.getKey()); String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式 return sign; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 处理支付结果通知 * @param request HTTP请求 * @return 处理结果 */ public PayResult processNotify(HttpServletRequest request) throws Exception { // 读取请求内容 BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8)); String line; StringBuilder xml = new StringBuilder(); while ((line = br.readLine()) != null) { xml.append(line); } br.close(); // 解析XML Map<String, String> resultMap = XMLUtil.xmlToMap(xml.toString()); // 验证签名 if (!verifySign(resultMap, wechatPayConfig.getKey())) { throw new Exception("微信支付签名验证失败"); } // 验证支付结果 if (!"SUCCESS".equals(resultMap.get("return_code")) || !"SUCCESS".equals(resultMap.get("result_code"))) { throw new Exception("微信支付结果异常"); } // 处理业务逻辑 PayResult payResult = new PayResult(); payResult.setOrderNumber(resultMap.get("out_trade_no")); payResult.setTransactionId(resultMap.get("transaction_id")); payResult.setTotalFee(resultMap.get("total_fee")); return payResult; } /** * 生成随机字符串 */ private String generateNonceStr() { return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); } /** * 微信支付API V2签名算法 * @param params 请求参数 * @param apiKey 商户API密钥 * @return 签名结果 */ public static String generateSign(Map<String, String> params, String apiKey) throws Exception { // 1. 过滤空值参数 Map<String, String> filteredParams = new HashMap<>(); for (Map.Entry<String, String> entry : params.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); // 排除sign字段和空值字段 if (!"sign".equals(key) && value != null && !value.isEmpty()) { filteredParams.put(key, value); } } // 2. 按照ASCII码排序参数名 List<String> keys = new ArrayList<>(filteredParams.keySet()); Collections.sort(keys); // 3. 构建签名原始字符串 StringBuilder sb = new StringBuilder(); for (String key : keys) { String value = filteredParams.get(key); sb.append(key).append("=").append(value).append("&"); } // 4. 添加API密钥 sb.append("key=").append(apiKey); // 5. MD5加密并转为大写 MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(sb.toString().getBytes("UTF-8")); // 6. 转换为十六进制字符串 StringBuilder sign = new StringBuilder(); for (byte b : digest) { sign.append(String.format("%02x", b & 0xff)); } return sign.toString().toUpperCase(); } /** * 验证签名 */ private boolean verifySign(Map<String, String> params, String key) throws Exception { String sign = params.get("sign"); if (StringUtils.isEmpty(sign)) { return false; } // 移除sign字段 Map<String, String> newParams = new HashMap<>(params); newParams.remove("sign"); // 生成新签名 String newSign = generateSign(newParams, key); return sign.equals(newSign); } /** * 关闭订单 */ public Map<String, String> closeOrder(String orderId){ // 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("appid", wechatPayConfig.getAppId()); params.put("mch_id", wechatPayConfig.getMchId()); params.put("nonce_str", generateNonceStr()); params.put("out_trade_no", orderId); // 生成签名 String sign = weixinSignature(params); params.put("sign", sign); // 将参数转换为XML String xmlParams = XMLUtil.mapToXml(params); // 发送请求到微信支付关闭订单接口 String url = "https://api.mch.weixin.qq.com/pay/closeorder"; String result = null; try { result = HttpUtil.post(url, xmlParams); } catch (Exception e) { throw new RuntimeException(e); } // 解析返回结果 try { return XMLUtil.xmlToMap(result); } catch (DocumentException e) { throw new RuntimeException(e); } } /** * 查询订单 */ public Map<String, String> queryOrder(String orderId) throws Exception { // 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("appid", wechatPayConfig.getAppId()); params.put("mch_id", wechatPayConfig.getMchId()); params.put("nonce_str", generateNonceStr()); params.put("out_trade_no", orderId); // 生成签名 String sign = generateSign(params, wechatPayConfig.getKey()); params.put("sign", sign); // 将参数转换为XML String xmlParams = XMLUtil.mapToXml(params); // 发送请求到微信支付查询订单接口 String url = "https://api.mch.weixin.qq.com/pay/orderquery"; String result = HttpUtil.post(url, xmlParams); // 解析返回结果 return XMLUtil.xmlToMap(result); } /** * 申请退款 - 使用证书 */ public Map<String, String> refund(String orderNo, String refundNo, String totalFee, String refundFee, String refundDesc,String callbackPath) { int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue(); int j = new BigDecimal(refundFee).multiply(new BigDecimal("100")).intValue(); try { // 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("appid", wechatPayConfig.getAppId()); params.put("mch_id", wechatPayConfig.getMchId()); params.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", "")); params.put("out_trade_no", orderNo); params.put("out_refund_no", refundNo); params.put("total_fee", String.valueOf(i)); params.put("refund_fee", String.valueOf(j)); params.put("refund_desc", refundDesc); params.put("notify_url", wechatPayConfig.getCallbackPath() + callbackPath); // 退款结果 // 生成签名 String sign = weixinSignature(params); params.put("sign", sign); // 转换为XML String xmlParams = XMLUtil.mapToXml(params); // 使用证书发送请求 String result = postWithCert("https://api.mch.weixin.qq.com/secapi/pay/refund", xmlParams); // 解析结果 Map<String, String> resultMap = XMLUtil.xmlToMap(result); System.out.println("申请退款结果"+resultMap); // 验证签名 if (!verifySign(resultMap, wechatPayConfig.getKey())) { resultMap.put("return_code","FAILED"); resultMap.put("return_msg","申请退款结果签名验证失败"); return resultMap; } return resultMap; } catch (Exception e) { Map<String, String> resultMap=new HashMap<>(); resultMap.put("return_code","FAILED"); resultMap.put("return_msg","申请退款失败"); return resultMap; } } /** * 使用证书发送请求 */ private String postWithCert(String url, String xmlData) throws Exception { // 证书类型为PKCS12 KeyStore keyStore = KeyStore.getInstance("PKCS12"); // 获取证书路径 String certPath = wechatPayConfig.getCertPath(); // 如果是classpath路径,使用ClassLoader加载 if (certPath.startsWith("classpath:")) { String path = certPath.substring("classpath:".length()); try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { if (inputStream == null) { throw new FileNotFoundException("证书文件不存在: " + path); } keyStore.load(inputStream, wechatPayConfig.getMchId().toCharArray()); } } else { // 传统文件路径 try (FileInputStream inputStream = new FileInputStream(new File(certPath))) { keyStore.load(inputStream, wechatPayConfig.getMchId().toCharArray()); } } // 实例化密钥库 & 初始化密钥工厂 SSLContext sslContext = SSLContext.getInstance("TLS"); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, wechatPayConfig.getMchId().toCharArray()); sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); // 创建HttpsURLConnection对象 URL httpsUrl = new URL(url); HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection(); conn.setSSLSocketFactory(sslContext.getSocketFactory()); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // 发送请求 OutputStream outputStream = conn.getOutputStream(); outputStream.write(xmlData.getBytes("UTF-8")); outputStream.flush(); outputStream.close(); // 获取响应 InputStream inputStream = conn.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); StringBuilder result = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { result.append(line); } bufferedReader.close(); inputStream.close(); conn.disconnect(); return result.toString(); } /** * 处理退款回调 */ public RefundCallbackResult processRefundCallback(String xmlData) { try { // 1. 解析回调XML数据 if (StringUtils.isEmpty(xmlData)) { return RefundCallbackResult.fail("回调数据为空"); } //2.解析参数 System.out.println(xmlData); System.out.println("----------------------------------------"); Map<String, String> resultMap = XMLUtil.xmlToMap(xmlData); System.out.println(resultMap.get("req_info")); // 3. 检查返回状态 String returnCode = resultMap.get("return_code"); if (!"SUCCESS".equals(returnCode)) { String errMsg = resultMap.get("return_msg"); return RefundCallbackResult.fail("通信失败:" + errMsg); } //4 使用商户API密钥解密req_info(AES-256-CBC算法) String decryptData = decrypt(resultMap.get("req_info"), wechatPayConfig.getKey()); Map<String, String> refundDetail = XMLUtil.xmlToMap(decryptData); // 4. 提取退款信息 String orderNo = refundDetail.get("out_trade_no"); // 原订单号 String refundNo = refundDetail.get("out_refund_no"); // 退款订单号 String refundId = refundDetail.get("refund_id"); // 微信退款ID System.err.println("退款回调成功,订单号:"+orderNo+",退款号:"+refundNo+",状态:{}"+refundId); RefundCallbackResult refundCallbackResult = RefundCallbackResult.success(); refundCallbackResult.setOrderNo(orderNo); refundCallbackResult.setRefundNo(refundId); return refundCallbackResult; } catch (Exception e) { return RefundCallbackResult.fail("系统异常:" + e.getMessage()); } } private static String wxDecrypt(String req_info, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException{ byte[] decode = Base64.getDecoder().decode(req_info); System.out.println(Arrays.toString(decode)); String sign = MD5AndKL.MD5Encode(key, "UTF-8").toLowerCase(); System.out.println(sign); if (Security.getProvider("BC") == null){ Security.addProvider(new BouncyCastleProvider()); } Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); SecretKeySpec secretKeySpec = new SecretKeySpec(sign.getBytes(), "AES"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); return new String(cipher.doFinal(decode)); } /** * 获取RSA加密公钥 */ public String getRsaPublicKey() { int maxRetries = 3; for (int retryCount = 0; retryCount < maxRetries; retryCount++) { try { System.out.println("尝试获取RSA公钥,第" + (retryCount + 1) + "次"); // 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("mch_id", wechatPayConfig.getMchId()); params.put("sign_type", "MD5"); params.put("nonce_str", generateNonceStr()); // 生成签名 String sign = weixinSignature(params); params.put("sign", sign); // 转换为XML String xmlParams = XMLUtil.mapToXml(params); // 打印请求参数 System.out.println("请求参数: " + xmlParams); // 使用证书发送请求(关键修改:使用postWithCert而非普通HTTP请求) String result = postWithCert("https://fraud.mch.weixin.qq.com/risk/getpublickey", xmlParams); // 打印响应结果 System.out.println("响应结果: " + result); // 解析结果 Map<String, String> resultMap = XMLUtil.xmlToMap(result); System.out.println("获取RSA公钥结果: " + resultMap); // 检查返回状态 if (!"SUCCESS".equals(resultMap.get("return_code"))) { throw new Exception("RSA公钥获取失败: " + resultMap.get("return_msg")); } // 保存公钥到本地文件 savePublicKeyToClasspath(resultMap.get("pub_key")); return resultMap.get("pub_key"); } catch (Exception e) { System.err.println("获取RSA公钥异常: " + e.getMessage() + ", 重试次数: " + (retryCount + 1)); e.printStackTrace(); // 如果是最后一次重试,抛出异常 if (retryCount == maxRetries - 1) { return null; } // 重试前等待一段时间 try { Thread.sleep(1000 * (retryCount + 1)); // 指数退避 } catch (InterruptedException ie) { Thread.currentThread().interrupt(); return null; } } } return null; } /** * 保存RSA公钥到文件夹 * @param publicKey RSA公钥内容 */ private static void savePublicKeyToClasspath(String publicKey) throws IOException { // 创建 cert 目录(如果不存在) Path certDir = Paths.get(CERT_FOLDER); if (!Files.exists(certDir)) { Files.createDirectories(certDir); // 自动创建目录 } // 写入公钥文件(UTF-8 编码) Path keyFile = certDir.resolve(RSA_PUBLIC_KEY_FILENAME); Files.write(keyFile, publicKey.getBytes(StandardCharsets.UTF_8)); } /** * 从文件夹加载RSA公钥 * @return RSA公钥内容 */ private static String loadPublicKeyFromClasspath() throws IOException { Path keyFile = Paths.get(CERT_FOLDER + RSA_PUBLIC_KEY_FILENAME); byte[] bytes = Files.readAllBytes(keyFile); // 读取所有字节 return new String(bytes, StandardCharsets.UTF_8); // 转为UTF-8字符串 } /** * 加载公钥 返回PublicKey对象 */ public static PublicKey loadPublicKey(String pemContent) throws Exception { // 读取PEM文件内容 // String pemContent = new String(Files.readAllBytes(Paths.get(CERT_FOLDER + RSA_PUBLIC_KEY_FILENAME)), StandardCharsets.UTF_8); // 移除PEM头尾标记 String publicKeyPEM = pemContent .replace("-----BEGIN RSA PUBLIC KEY-----", "") .replace("-----END RSA PUBLIC KEY-----", "") .replaceAll("\\s", ""); // 去除换行/空格 // 解码Base64 byte[] encoded = Base64.getDecoder().decode(publicKeyPEM); // 手动解析PKCS#1格式 DerInputStream derReader = new DerInputStream(encoded); DerValue[] seq = derReader.getSequence(0); BigInteger modulus = seq[0].getBigInteger(); BigInteger exponent = seq[1].getBigInteger(); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent); return KeyFactory.getInstance("RSA").generatePublic(keySpec); } /** * 使用RSA-OAEP加密数据 * @param plaintext 待加密的明文 * @return Base64编码的密文 */ public static String encrypt(String plaintext, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encryptedBytes); } /** * 商户付款到银行卡(优先使用本地保存的公钥) * @param partnerTradeNo 商户订单号 * @param bankNo 银行卡号 * @param trueName 银行卡真实姓名 * @param bankCode 银行编码 * @param amount 金额(分) * @param desc 付款说明 * @return 付款结果 */ public Map<String, String> payToBankCard(String partnerTradeNo, String bankNo, String trueName, String bankCode, BigDecimal amount, String desc) throws Exception { int i = amount.multiply(new BigDecimal("100")).intValue(); // 1. 尝试从本地加载RSA公钥 String pubKey = loadPublicKeyFromClasspath(); // 2. 如果本地没有公钥或公钥无效,则从微信获取新公钥 if (pubKey == null || pubKey.isEmpty()) { pubKey = getRsaPublicKey(); } //公钥对象 PublicKey publicKey = loadPublicKey(pubKey); // 3. 使用RSA公钥加密银行卡号和真实姓名 String encryptedBankNo = encrypt(bankNo, publicKey); String encryptedTrueName = encrypt(trueName, publicKey); // 4. 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("mch_id", wechatPayConfig.getMchId()); params.put("partner_trade_no", partnerTradeNo); params.put("enc_bank_no", encryptedBankNo); params.put("enc_true_name", encryptedTrueName); params.put("bank_code", bankCode); params.put("amount", String.valueOf(i)); params.put("desc", desc); params.put("nonce_str", generateNonceStr()); // 生成签名 String sign = weixinSignature(params); params.put("sign", sign); // 将参数转换为XML String xmlParams = XMLUtil.mapToXml(params); // 5. 发送请求到微信支付付款到银行卡接口 String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank"; String result = postWithCert(url, xmlParams); // 解析返回结果 Map<String, String> resultMap = XMLUtil.xmlToMap(result); // 验证签名 if (!verifySign(resultMap, wechatPayConfig.getKey())) { throw new Exception("付款到银行卡签名验证失败"); } return resultMap; } public static void main(String[] args) throws IOException { String info="CjlaS7RVnPn7zzP5ByZDxUN7OrXGp1/DEdO0qahpIqDH/gTNHb/U7VmrVV0S4lXrIa0N8FEREC3CdIeT4XB5P4D0E8TSURu6J/cD01hFu28f0JDRfeips3vSpTgznRGyCfnUBDPYwyrVeP29Wac7WAb3CCcJf7OZWaweOUkaKjaBRa1GzMZcguSZnQJz0cD5Jb4HbTMvM0VAebfCY9aXdfFBIbm+cPYESo3awqwkNTQeT4V+FViw8f8sjkH0TScMgWBiSKmQC837BLD27yIGklqlYkDP2IMeiNw+b12qCAGszfp2vYd3X+HpViXkQQet3PJWYlAm55R+IgvschP7Ub65XzLINfQrJKrQUXiKKO2LwoSRSwZvfDkR8G8E8X59CnU2XvWKeos5Y0q8ckbJb97yI+09nNgMjYyJoVCVjTFgFMDEQ4+e3CpYRhD6V/3RBp+TvBwszldbRav2XEuCXL2kCJyJEAqLPMNyfYBSNF8z1btjyz0+y/xQQcySKlQInZ710FxSE7KwRSBQ92j9nDdlR7UxCrPVCkEd+GrVNSqqnyjNh1J/rPJPHvvGwkPPq72TKiw6ZgaIgIDhy0/lWHTclo4sjYAWuUVfg3CJ8dqkuQwVZ7i0+NiahIl78RtcUph8NR48yUgBkN7WhCcu5wLbg2tu8Qe0SIwHF+RW1x9Yc8akEkNbMd4xzs8lY5MYEU9V16U8RyWJuwPDph3RnmV8HQ+2hfzmjCvPkBwtfR8P5VdK86OIsHfnfQxAcPM2a86tOBBzFXPrLHgd2CRcDKH+MXTw7RSH/bk1PiMUAWF8TQsNDzgUlznJnkjiQxoym/4ZUf4C6072KKQHbp6bgBYkBhJLT2lmjVMNSX5b1SXM9eTQixRfq6MKGw3P8XJnKdofktVv+KtSzWQlW0C8p504NWACiExupF5EII7FG+xCWt7urWUbc4NRI36UFrKToQCLVv6UBCXt/t9iWlvs6SfuZhpCexeMmZWeiIldzRu87U9rXR46Hu7DAL8dZ+0ItsIZYThSIABzZgaLKggXlkjyAcbcPYKO7egrCmDtFhzHuh4uA3VeBylL3/ZLZ4FUedn/8L4e2iAu22Qj46ORlu17W5R8Ez9kubydeAgC9PkWnjptaubPxE0bjPN69tec"; String key="fD0JzscfMf295SYtRK3MnPRjSCA4Gahr"; try { String decrypted = decrypt(info, key); System.out.println("解密结果: " + decrypted); } catch (Exception e) { throw new RuntimeException(e); } } public static String decrypt(String encryptedStringA, String merchantKey) throws Exception { // 1. 对加密串A做base64解码,得到加密串B byte[] decode = Base64.getDecoder().decode(encryptedStringA); // 2. 对商户key做md5,得到32位小写key* String sign = MD5AndKL.MD5Encode(merchantKey, "UTF-8").toLowerCase(); // 3. 确保BouncyCastle提供者已添加 if (Security.getProvider("BC") == null) { Security.addProvider(new BouncyCastleProvider()); } // 4. 使用AES-256-ECB解密(PKCS7Padding) Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); // 注意:微信要求使用AES-256,所以密钥应为32字节(256位) // 如果MD5结果是32字节(256位),直接使用 byte[] aesKey = sign.getBytes(StandardCharsets.UTF_8); SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); // 执行解密并指定UTF-8编码 byte[] decryptedBytes = cipher.doFinal(decode); return new String(decryptedBytes, StandardCharsets.UTF_8); } } ruoyi-system/src/main/java/com/ruoyi/system/wx/XMLUtil.java
New file @@ -0,0 +1,52 @@ package com.ruoyi.system.wx; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * XML工具类 */ public class XMLUtil { /** * 将Map转换为XML字符串 */ public static String mapToXml(Map<String, String> params) { Document document = DocumentHelper.createDocument(); // 禁用XML声明 document.setXMLEncoding(null); // 关键设置 Element root = document.addElement("xml"); for (Map.Entry<String, String> entry : params.entrySet()) { String key = entry.getKey(); String value = entry.getValue() != null ? entry.getValue() : ""; root.addElement(key).setText(value); } return document.asXML(); } /** * 将XML字符串转换为Map */ public static Map<String, String> xmlToMap(String xmlStr) throws DocumentException { Map<String, String> map = new HashMap<>(); Document document = DocumentHelper.parseText(xmlStr); Element root = document.getRootElement(); for (Iterator<?> iterator = root.elementIterator(); iterator.hasNext();) { Element element = (Element) iterator.next(); // 关键修改:获取元素内所有内容(包括CDATA) String value = element.getStringValue(); // 自动处理CDATA map.put(element.getName(), value); } return map; } } ruoyi-system/src/main/resources/cert/apiclient_cert.p12Binary files differ
ruoyi-system/src/main/resources/cert/apiclient_cert.pem
New file @@ -0,0 +1,25 @@ -----BEGIN CERTIFICATE----- MIIEJDCCAwygAwIBAgIUPzcz2XhuGAdLsR4fKcRiVtSVTEkwDQYJKoZIhvcNAQEL BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg Q0EwHhcNMjUwNjIzMDkwNDI4WhcNMzAwNjIyMDkwNDI4WjB+MRMwEQYDVQQDDAox NzIwNTUyNjk4MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xKjAoBgNVBAsM IeWbm+W3neS4gOivgeaIkOenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBhMCQ04x ETAPBgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAu5sppa1rG+Xc0XPW78kKw0Bq+oYjuzEfjh3pwurmwrOsqmPaQj4aHXS8M2eW nRG6oP4BR3dQnphDRCGTdBoVTHOrNJt3xBJ+iSkbnQLH7aHhymyZxo5bZ7q9LnzZ SMqojYJ9CoDeriubrNWR5pXTB02xJsSPXKo4KwrJIgUQJ0bc2EuyngwZ5rJKeetW yA7Pw4NZ5X3X0iBXTfhItaW1RLcBegny+K14AneYjpvAqMt3ynV6xQqvl3s0dCDr 8Bo33ds0vi1dr40gM7HvBaQ2oMXIvVdl4xX1H4OM84JwVOKyG/hTC9PWIznxV+es vDKenuBhRJ0I1N/fy7q0aYDiIwIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0P BAQDAgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1 cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFE Mzk3NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMz QTg3QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBAAiJH9rQLYd9 3OX8FDxGLetiUd8tIS+Y3fjZhxYiGTF6wz6mR5L3RMYqxZcbb2OWFi1dzYQ97lrY 1spt4+1a5pjeMNlEX9hPUVriWTDN0YhNIvQ2vQ3IbXgWTve0cuwSfc/cyWqhdSCq 7V7jzVs+LRewXsvUyXgqG3Tshzadhi6CL1njAa3PUcSkzgLHKptaD/3irx/nniLB j6ktq7e/0Orj3BJYQueYtA0LZrk3OacnbDiIeHgw6qLGounfSHbuIWSSLUa6ghW9 JovmWWENapQF7kT6kh+FalMi0au1xpgKnEgRDjuVyXt9PfLWi+2GWKtsy2gLCzq7 wS2ob3v4ey8= -----END CERTIFICATE----- ruoyi-system/src/main/resources/cert/apiclient_key.pem
New file @@ -0,0 +1,28 @@ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7mymlrWsb5dzR c9bvyQrDQGr6hiO7MR+OHenC6ubCs6yqY9pCPhoddLwzZ5adEbqg/gFHd1CemENE IZN0GhVMc6s0m3fEEn6JKRudAsftoeHKbJnGjltnur0ufNlIyqiNgn0KgN6uK5us 1ZHmldMHTbEmxI9cqjgrCskiBRAnRtzYS7KeDBnmskp561bIDs/Dg1nlfdfSIFdN +Ei1pbVEtwF6CfL4rXgCd5iOm8Coy3fKdXrFCq+XezR0IOvwGjfd2zS+LV2vjSAz se8FpDagxci9V2XjFfUfg4zzgnBU4rIb+FML09YjOfFX56y8Mp6e4GFEnQjU39/L urRpgOIjAgMBAAECggEBAIn+kd3J97UnmQt/16O9D2ubYJUyQeoZMgrJOf8j5eVl YCZdGFgNcgwkp6JwGbsjJVHyRGKbAvQFL8VXpSyLWwtHMbGagbf5mpWtZSBSwVir 8HeC9oG0iMt98lXVg8YlO2ILj4pATIt0jCfPWGhx4C3JGftYLdONaY9Pea7KZp1c IgOsXA84+7V+ndyOTDbXTot6UOjOccwfQ3qUHDtCWmGoauoO0ftCqMa4SxADKiMg auQup9wYpApnqvIZuD2TzXUCGjXxmfTYM9pesrq11zWH2u7vJ6fbFLlM+zKgmxkp lqIWChDpzMrUjMaAW4ufIN/ekuGMdAyYKGET3pK5F2ECgYEA2zLGzwB6BZ87ponR bcULQCQ6dsZt6X+dTSTO6Qopsabcdxtqb5W0iopMSVK18byV6eVZxYIUaHnATIry KKpLEM4N0ghjG6e0zv2yGEXfdEnmGAy/HPaRh2osPT9zXA+Kofliv9MUbIb4h+bl EtGOsIlp/juUOoBPh3kGAUkvOAsCgYEA2xqKS/LaNnHUR38SHvCJKAJlZxqFFAuf AdL2jCo5BKsFAt0BOhx/gdaw7z0uf4oGYs1RxOcF9Cun6IHC+mvM8tKrbyL0Xv3x /syEuVpjJtxSctQUVgOq14jqJSsBZpMr8bJhK3sAs7BoPqIFPCoTljtGxL+lb+9o VIkQMQvzFUkCgYBC2zDiMD4HevLBr+Vtupzc2m/ujEU349GBlwl48L2YztENjxIe qKWhX982ugB+k8uRxH9mC2/YEdKCRhroJlCw9ngmqKI57CPswlpQpvcpy+RfT3v3 BImMqOiHYdP4r1DUaHEjGulu1Jf3M4iI/dusoqzuexOR6FLZeiNHvx+k0wKBgFD2 YK4p4hqGO3Pj77VBGt2O7RuJQC2lEa+h3frzSzh/XY2uTtrDVxaKV70/tWPpg+yU hCenWprcWuJeuMbCeOwtjq21k+laG0cVGeJIFSVx+oF1/sG9/y4/6I2tc4oMzgs0 6BUiEaNUh2DFi/usbKpx4vem/aH8LGg4caQ+DygJAoGBAJsZ265oRTC2LshrGVeD yXCmTs4DjkK7EXgMrl8OyIymG64XdEUnpnN50dvFYnW2a7jlUhzBcwVAf4/gJ0k4 gfymOwkk9dsAUEkuiWXNVpUFi1Fdf39ADqeh3kwRpbBnOv3bwJ7h+i8i590TIGNK RINSd54kN0iLwgVC5/d+lSv1 -----END PRIVATE KEY----- ruoyi-system/src/main/resources/mapper/system/AppUserMapper.xml
@@ -19,8 +19,9 @@ left join (select user_id, count(1) as num from tb_order where status = 6 group by user_id) buy on tbu.id = buy.user_id left join (select c.user_id,count(o.company_id) as num from tb_company c left join tb_order o on c.id=o.company_id and o.status=6 group by c.user_id) sell on tbu.id = sell.user_id where tbu.is_delete =0 <if test="null != dto.username and dto.username != '' "> and tbu.user_name like concat('%',#{dto.username},'%') and tbu.status != 3 <if test="null != dto.userName and dto.userName != '' "> and tbu.user_name like concat('%',#{dto.userName},'%') </if> <if test="null != dto.phone and dto.phone != '' "> and tbu.phone like concat('%',#{dto.phone},'%') ruoyi-system/src/main/resources/mapper/system/OrderMapper.xml
@@ -7,86 +7,84 @@ select COALESCE(SUM(commission_price), 0.00) AS total_commission from tb_order where status in (4,5) and share_user_id =#{id} </select> <select id="getOrderPage" resultType="com.ruoyi.system.pojo.vo.OrderPageVO"> select c.id, o.order_no, publish.user_name as publishName, publish.phone as publishPhone, o.price, book.user_name as bookName, book.phone as bookPhone, c.create_time as createTime, o.create_time as bookTime, o.finish_time as finishTime, -- 状态映射逻辑 SELECT c.id, o.order_no, publish.user_name AS publishName, publish.phone AS publishPhone, o.price, book.user_name AS bookName, book.phone AS bookPhone, c.create_time AS createTime, o.create_time AS bookTime, o.finish_time AS finishTime, -- 状态映射逻辑 CASE WHEN c.status = -1 THEN -1 WHEN c.status = 1 THEN 1 WHEN c.status = 2 THEN 7 WHEN c.status = 3 THEN 6 WHEN c.status = 4 THEN CASE WHEN o.status = 1 THEN 1 WHEN o.status = 2 THEN 2 WHEN o.status = 3 THEN 3 WHEN o.status IN (4, 5) THEN 4 WHEN o.status = 6 THEN 6 ELSE c.status END ELSE c.status END AS status FROM tb_company c LEFT JOIN tb_order o ON o.company_id = c.id AND o.status != -1 LEFT JOIN (SELECT id, user_name, phone FROM tb_user GROUP BY id) publish ON c.user_id = publish.id LEFT JOIN (SELECT id, user_name, phone FROM tb_user GROUP BY id) book ON o.user_id = book.id WHERE c.is_delete = 0 <if test="null != dto.orderNo"> AND o.order_no LIKE CONCAT('%', #{dto.orderNo}, '%') </if> <if test="null != dto.publishName and '' != dto.publishName"> AND publish.user_name LIKE CONCAT('%', #{dto.publishName}, '%') </if> <if test="null != dto.publishPhone and '' != dto.publishPhone"> AND publish.phone LIKE CONCAT('%', #{dto.publishPhone}, '%') </if> <if test="null != dto.bookName and '' != dto.bookName"> AND book.user_name LIKE CONCAT('%', #{dto.bookName}, '%') </if> <if test="null != dto.bookPhone and '' != dto.bookPhone"> AND book.phone LIKE CONCAT('%', #{dto.bookPhone}, '%') </if> <if test="null != dto.createTimeStart and null != dto.createTimeEnd"> AND c.create_time BETWEEN #{dto.createTimeStart} AND #{dto.createTimeEnd} </if> <if test="null != dto.bookTimeStart and null != dto.bookTimeEnd"> AND o.create_time BETWEEN #{dto.bookTimeStart} AND #{dto.bookTimeEnd} </if> <if test="null != dto.finishTimeStart and null != dto.finishTimeEnd"> AND o.finish_time BETWEEN #{dto.finishTimeStart} AND #{dto.finishTimeEnd} </if> <if test="null != dto.status"> AND ( -- 直接匹配原始状态 (c.status IN (1,2,3) AND CASE WHEN c.status = 1 THEN 1 WHEN c.status = 2 THEN 6 WHEN c.status = 3 THEN 5 WHEN c.status = 4 THEN CASE WHEN o.status = 2 THEN 2 WHEN o.status = 3 THEN 3 WHEN o.status IN (4, 5) THEN 4 ELSE c.status -- 默认保持原状态(可根据需求调整) END ELSE c.status -- 其他状态保持不变 END AS status from tb_company c left join tb_order o on c.id = o.company_id and o.status != -1 left join (select id,user_name,phone from tb_user group by id) publish on c.user_id = publish.id left join (select id,user_name,phone from tb_user group by id) book on o.user_id = book.id where c.is_delete=0 <if test="null != dto.orderNo"> and o.order_no like concat('%',#{dto.orderNo},'%') </if> <if test="null != dto.publishName and '' != dto.publishName"> and publish.user_name like concat('%',#{dto.publishName},'%') </if> <if test="null != dto.publishPhone and '' != dto.publishPhone"> and publish.phone like concat('%',#{dto.publishPhone},'%') </if> <if test="null != dto.bookName and '' != dto.bookName"> and book.user_name like concat('%',#{dto.bookName},'%') </if> <if test="null != dto.bookPhone and '' != dto.bookPhone"> and book.phone like concat('%',#{dto.bookPhone},'%') </if> <if test="null != dto.createTimeStart and null != dto.createTimeEnd"> and c.create_time between #{dto.createTimeStart} and #{dto.createTimeEnd} </if> <if test="null != dto.bookTimeStart and null != dto.bookTimeEnd"> and o.create_time between #{dto.bookTimeStart} and #{dto.bookTimeEnd} </if> <if test="null != dto.finishTimeStart and null != dto.finishTimeEnd"> and o.finish_time between #{dto.finishTimeStart} and #{dto.finishTimeEnd} </if> <if test="null != dto.status"> AND ( <!-- 直接匹配原始状态 --> (c.status IN (1,2,3) AND CASE WHEN c.status = 1 THEN 1 WHEN c.status = 2 THEN 6 WHEN c.status = 3 THEN 5 ELSE c.status END = #{dto.status}) <!-- 匹配映射后的状态4(c.status=4且o.status=4/5) --> OR (c.status = 4 AND o.status IN (4,5) AND 4 = #{dto.status}) <!-- 匹配映射后的状态2(c.status=4且o.status=2) --> OR (c.status = 4 AND o.status = 2 AND 2 = #{dto.status}) <!-- 匹配映射后的状态3(c.status=4且o.status=3) --> OR (c.status = 4 AND o.status = 3 AND 3 = #{dto.status}) ) </if> WHEN c.status = 1 THEN 1 WHEN c.status = 2 THEN 6 WHEN c.status = 3 THEN 5 ELSE c.status END = #{dto.status}) -- 匹配映射后的状态4(c.status=4且o.status=4/5) OR (c.status = 4 AND o.status IN (4,5) AND 4 = #{dto.status}) -- 匹配映射后的状态2(c.status=4且o.status=2) OR (c.status = 4 AND o.status = 2 AND 2 = #{dto.status}) -- 匹配映射后的状态3(c.status=4且o.status=3) OR (c.status = 4 AND o.status = 3 AND 3 = #{dto.status}) ) order by c.create_time,o.create_time </if> </select> <select id="getDetailById" resultType="com.ruoyi.system.pojo.vo.OrderDetailVO"> @@ -95,8 +93,8 @@ -- 状态映射逻辑 CASE WHEN c.status = 1 THEN 1 WHEN c.status = 2 THEN 6 WHEN c.status = 3 THEN 5 WHEN c.status = 2 THEN 7 WHEN c.status = 3 THEN 6 WHEN c.status = 4 THEN CASE WHEN o.status = 2 THEN 2 @@ -107,6 +105,7 @@ ELSE c.status -- 其他状态保持不变 END AS status, o.id as orderId, c.company_name, c.establish_time, concat(c.city,c.province,c.area) as place, @@ -144,8 +143,8 @@ ( CASE WHEN c.status = 1 THEN 1 WHEN c.status = 2 THEN 6 WHEN c.status = 3 THEN 5 WHEN c.status = 2 THEN 7 WHEN c.status = 3 THEN 6 WHEN c.status = 4 THEN CASE WHEN o.status = 2 THEN 2 @@ -204,6 +203,13 @@ FROM tb_order WHERE status IN (4, 5, 6) AND is_refund = 0 <if test="null != dto.orderNo and '' != dto.orderNo"> and order_no LIKE CONCAT('%', #{dto.orderNo}, '%') </if> <if test="null != dto.operateTimeStart and null != dto.operateTimeEnd"> and pay_time between #{dto.operateTimeStart} and #{dto.operateTimeEnd} </if> AND ( #{dto.type} IS NULL OR 1 = #{dto.type} ) </select> <select id="flowsPage" resultType="com.ruoyi.system.pojo.vo.FinanceFlowsPageVO"> SELECT @@ -225,7 +231,7 @@ <if test="null != dto.operateTimeStart and null != dto.operateTimeEnd"> and pay_time between #{dto.operateTimeStart} and #{dto.operateTimeEnd} </if> AND ( #{dto.type} IS NULL OR 1 = #{dto.type} ) AND ( #{dto.type} IS NULL OR 1 = #{dto.type} ) UNION ALL SELECT order_no, @@ -243,9 +249,9 @@ <if test="null != dto.operateTimeStart and null != dto.operateTimeEnd"> and refund_time between #{dto.operateTimeStart} and #{dto.operateTimeEnd} </if> AND ( #{dto.type} IS NULL OR 2 = #{dto.type} ) AND ( #{dto.type} IS NULL OR 2 = #{dto.type} ) ORDER BY operateTime DESC LIMIT #{dto.pageNum}, #{dto.pageSize}; LIMIT #{dto.offset}, #{dto.pageSize}; </select> <select id="countFlowsPage" resultType="java.lang.Long"> SELECT COUNT(*) FROM ( ruoyi-system/src/main/resources/mapper/system/QuestionMapper.xml
@@ -4,12 +4,12 @@ <select id="getQuestionPage" resultType="com.ruoyi.system.pojo.vo.QuestionPageVO"> select id,name ,order_num select id,title ,order_num from tb_question where del_flg=0 <if test="null != name and '' != name"> and name like concat('%',#{name},'%') del_flag=0 <if test="null != title and '' != title"> and title like concat('%',#{title},'%') </if> </select> ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -142,6 +142,21 @@ where sm.parent_id = 0 order by sm.order_num asc </select> <select id="selectMenusByUserId" resultType="com.ruoyi.common.core.domain.entity.SysMenu"> select m.menu_id, m.parent_id from sys_user_role ur left join sys_role_menu rm on ur.role_id = rm.role_id left join sys_menu m on rm.menu_id = m.menu_id where ur.user_id=#{userId} </select> <select id="getPathsByMenuIds" resultType="java.lang.String"> select path from sys_menu where menu_id in <foreach collection='ids' item='id' open='(' separator=',' close=')'> #{id} </foreach> </select> <update id="updateMenu" parameterType="SysMenu"> update sys_menu ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
@@ -14,9 +14,12 @@ </select> <select id="selectMenuIdsByRoleIds" resultType="java.lang.Long"> select menu_id from sys_role_menu where role_id in <foreach collection="roleList" item="roleId" open="(" separator="," close=")"> #{roleId} </foreach> <if test="roleList != null and !roleList.isEmpty"> <foreach collection="roleList" item="roleId" open="(" separator="," close=")"> #{roleId} </foreach> </if> </select> <delete id="deleteRoleMenuByRoleId" parameterType="Long"> ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -123,7 +123,7 @@ <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult"> <include refid="selectUserVo"/> where u.user_name = #{userName} and u.del_flag = '0' where u.phonenumber = #{userName} </select> <select id="selectUserById" parameterType="Long" resultMap="SysUserResult">