From 607e4ab169b003991ed4788c9dbe0bd1fefc69f3 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期三, 29 七月 2026 23:26:56 +0800
Subject: [PATCH] 各类修复
---
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/PartnerTypeRoleService.java | 122 ++++++++++++
ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/service/impl/SiteServiceImplTest.java | 49 ++++
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java | 4
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/util/task/AccountSettlementIncomeTest.java | 8
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java | 4
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java | 14
docs/superpowers/plans/2026-07-29-partner-type-role-sync.md | 50 +++++
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java | 4
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml | 27 ++
ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/PartnerTypeRoleServiceTest.java | 140 ++++++++++++++
sql/20260728_account_settlement_v2.sql | 1
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java | 13 +
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java | 2
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/AccountListVO.java | 2
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java | 6
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java | 28 --
ruoyi-modules/ruoyi-system/pom.xml | 7
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml | 68 ++++--
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/AccountSettlementStatementMapperTest.java | 45 ++++
19 files changed, 531 insertions(+), 63 deletions(-)
diff --git a/docs/superpowers/plans/2026-07-29-partner-type-role-sync.md b/docs/superpowers/plans/2026-07-29-partner-type-role-sync.md
new file mode 100644
index 0000000..8eccdf6
--- /dev/null
+++ b/docs/superpowers/plans/2026-07-29-partner-type-role-sync.md
@@ -0,0 +1,50 @@
+# Partner Type Role Sync Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Ensure partner accounts automatically receive the enabled system role matching their partner type whenever user permissions are loaded.
+
+**Architecture:** Add a focused system-service component that resolves the current partner type through the existing charging-pile Feign client and synchronizes only the three built-in type roles in `sys_user_role`. Call it before login/current-user permissions are calculated, then reload the user so its role collection and menu permissions reflect the synchronized database state.
+
+**Tech Stack:** Java 8, Spring Boot, MyBatis-Plus, OpenFeign, JUnit 5, Mockito
+
+## Global Constraints
+
+- Partner type `1` maps to role key `independent_partner`.
+- Partner type `2` maps to role key `site_owner`.
+- Partner type `3` maps to role key `service_provider`.
+- Preserve roles outside these three built-in type roles.
+- Remove stale built-in type roles when the partner type changes.
+- Do not modify unrelated existing workspace changes.
+
+---
+
+### Task 1: Partner type role synchronizer
+
+**Files:**
+- Create: `ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/PartnerTypeRoleService.java`
+- Test: `ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/PartnerTypeRoleServiceTest.java`
+
+**Interfaces:**
+- Consumes: `SiteClient.getPartnerR(Integer)`, `ISysRoleService`, and `ISysUserRoleService`.
+- Produces: `void synchronize(SysUser user)`.
+
+- [x] **Step 1: Write failing tests for all three mappings, custom-role preservation, stale built-in-role removal, non-partner bypass, and missing-role failure.**
+- [x] **Step 2: Run `mvn -pl ruoyi-modules/ruoyi-system -am -Dtest=PartnerTypeRoleServiceTest -Dsurefire.failIfNoSpecifiedTests=false test` and verify the new tests fail before implementation.**
+- [x] **Step 3: Implement role-key mapping and idempotent `sys_user_role` synchronization.**
+- [x] **Step 4: Run the focused test and verify it passes.**
+
+### Task 2: Permission-loading integration
+
+**Files:**
+- Modify: `ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java`
+- Test: `ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/PartnerTypeRoleServiceTest.java`
+
+**Interfaces:**
+- Consumes: `PartnerTypeRoleService.synchronize(SysUser)`.
+- Produces: login and current-user responses whose roles and permissions include the matching partner-type role.
+
+- [x] **Step 1: Invoke synchronization in both `/user/info/{username}` and `/user/getInfo` before permission calculation.**
+- [x] **Step 2: Reload `SysUser` after synchronization so `SysUser.roles` is current.**
+- [x] **Step 3: Run the focused test and compile the system module.**
+- [x] **Step 4: Review the diff to confirm unrelated working-tree changes remain untouched.**
diff --git a/ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/AccountListVO.java b/ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/AccountListVO.java
index 9d65389..04f0900 100644
--- a/ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/AccountListVO.java
+++ b/ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/AccountListVO.java
@@ -1,9 +1,7 @@
package com.ruoyi.order.api.vo;
import com.ruoyi.common.core.web.page.PageInfo;
-import com.ruoyi.order.api.model.TChargingBill;
import com.ruoyi.order.api.model.TChargingOrder;
-import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml
index 37af99a..56a85a6 100644
--- a/ruoyi-modules/ruoyi-system/pom.xml
+++ b/ruoyi-modules/ruoyi-system/pom.xml
@@ -145,6 +145,11 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api-chargingPile</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
@@ -177,4 +182,4 @@
</resources>
</build>
-</project>
\ No newline at end of file
+</project>
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
index 275c851..17d73e9 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
@@ -339,8 +339,8 @@
@ApiOperation(value = "编辑角色", tags = {"管理后台-角色管理"})
public AjaxResult roleUpdate(@Validated @RequestBody RoleUpdateDto dto) {
SysRole oldRole = roleService.selectRoleById(dto.getRoleId());
- if (isSystemBuiltinRole(oldRole)) {
- return AjaxResult.error("系统内置角色不可编辑");
+ if (oldRole != null && oldRole.isAdmin()) {
+ return AjaxResult.error("超级管理员角色不可编辑");
}
SysRole role = new SysRole();
role.setRoleName(dto.getRoleName());
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
index 9788e50..d983e2a 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
@@ -72,6 +72,9 @@
private ISysPermissionService permissionService;
@Resource
+ private PartnerTypeRoleService partnerTypeRoleService;
+
+ @Resource
private ISysConfigService configService;
@Resource
@@ -505,6 +508,7 @@
if (StringUtils.isNull(sysUser)) {
return R.fail("用户名/密码错误");
}
+ sysUser = synchronizePartnerTypeRole(sysUser);
// 角色集合
Set<String> roles = permissionService.getRolePermission(sysUser);
// 权限集合
@@ -539,6 +543,7 @@
@GetMapping("/getInfo")
public AjaxResult getInfo() {
SysUser user = userService.selectUserById(tokenService.getLoginUser().getUserid());
+ user = synchronizePartnerTypeRole(user);
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合
@@ -550,6 +555,14 @@
return ajax;
}
+ private SysUser synchronizePartnerTypeRole(SysUser user) {
+ partnerTypeRoleService.synchronize(user);
+ if (user != null && Integer.valueOf(2).equals(user.getRoleType()) && user.getObjectId() != null) {
+ return userService.selectUserById(user.getUserId());
+ }
+ return user;
+ }
+
/**
* 发送重置密码验证码
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/PartnerTypeRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/PartnerTypeRoleService.java
new file mode 100644
index 0000000..1d4cde2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/PartnerTypeRoleService.java
@@ -0,0 +1,122 @@
+package com.ruoyi.system.service;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.chargingPile.api.feignClient.SiteClient;
+import com.ruoyi.chargingPile.api.model.Partner;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.exception.ServiceException;
+import com.ruoyi.system.api.domain.SysRole;
+import com.ruoyi.system.api.domain.SysUser;
+import com.ruoyi.system.domain.SysUserRole;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Synchronizes the built-in role granted to a partner account from its partner type.
+ */
+@Service
+public class PartnerTypeRoleService {
+
+ static final String INDEPENDENT_PARTNER_ROLE_KEY = "independent_partner";
+ static final String SITE_OWNER_ROLE_KEY = "site_owner";
+ static final String SERVICE_PROVIDER_ROLE_KEY = "service_provider";
+
+ private static final Set<String> PARTNER_ROLE_KEYS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+ INDEPENDENT_PARTNER_ROLE_KEY,
+ SITE_OWNER_ROLE_KEY,
+ SERVICE_PROVIDER_ROLE_KEY
+ )));
+
+ private static final Map<Integer, String> PARTNER_TYPE_ROLE_KEYS;
+
+ static {
+ Map<Integer, String> roleKeys = new HashMap<>();
+ roleKeys.put(1, INDEPENDENT_PARTNER_ROLE_KEY);
+ roleKeys.put(2, SITE_OWNER_ROLE_KEY);
+ roleKeys.put(3, SERVICE_PROVIDER_ROLE_KEY);
+ PARTNER_TYPE_ROLE_KEYS = Collections.unmodifiableMap(roleKeys);
+ }
+
+ private final SiteClient siteClient;
+ private final ISysRoleService roleService;
+ private final ISysUserRoleService userRoleService;
+
+ public PartnerTypeRoleService(SiteClient siteClient,
+ ISysRoleService roleService,
+ ISysUserRoleService userRoleService) {
+ this.siteClient = siteClient;
+ this.roleService = roleService;
+ this.userRoleService = userRoleService;
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void synchronize(SysUser user) {
+ if (!isPartnerAccount(user)) {
+ return;
+ }
+
+ R<Partner> partnerResult = siteClient.getPartnerR(user.getObjectId());
+ Partner partner = partnerResult == null ? null : partnerResult.getData();
+ if (partner == null) {
+ throw new ServiceException("当前账号关联的合作商不存在");
+ }
+
+ String targetRoleKey = PARTNER_TYPE_ROLE_KEYS.get(partner.getPartnerType());
+ if (targetRoleKey == null) {
+ throw new ServiceException("当前合作商类型无效");
+ }
+
+ List<SysRole> builtInRoles = roleService.list(Wrappers.lambdaQuery(SysRole.class)
+ .in(SysRole::getRoleKey, PARTNER_ROLE_KEYS)
+ .eq(SysRole::getDelFlag, "0")
+ .eq(SysRole::getStatus, "0"));
+ Map<String, SysRole> roleByKey = builtInRoles.stream()
+ .collect(Collectors.toMap(SysRole::getRoleKey, role -> role, (first, ignored) -> first));
+ SysRole targetRole = roleByKey.get(targetRoleKey);
+ if (targetRole == null) {
+ throw new ServiceException("系统角色【" + targetRoleKey + "】不存在或已停用,请先配置角色");
+ }
+
+ Set<Long> builtInRoleIds = builtInRoles.stream()
+ .map(SysRole::getRoleId)
+ .collect(Collectors.toSet());
+ List<SysUserRole> existingRoles = userRoleService.list(Wrappers.lambdaQuery(SysUserRole.class)
+ .eq(SysUserRole::getUserId, user.getUserId())
+ .in(SysUserRole::getRoleId, builtInRoleIds));
+
+ boolean hasTargetRole = false;
+ for (SysUserRole existingRole : existingRoles) {
+ Long existingRoleId = existingRole.getRoleId();
+ if (targetRole.getRoleId().equals(existingRoleId)) {
+ hasTargetRole = true;
+ } else if (builtInRoleIds.contains(existingRoleId)) {
+ userRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class)
+ .eq(SysUserRole::getUserId, user.getUserId())
+ .eq(SysUserRole::getRoleId, existingRoleId));
+ }
+ }
+
+ if (!hasTargetRole) {
+ SysUserRole userRole = new SysUserRole();
+ userRole.setUserId(user.getUserId());
+ userRole.setRoleId(targetRole.getRoleId());
+ userRoleService.save(userRole);
+ }
+ }
+
+ private boolean isPartnerAccount(SysUser user) {
+ return user != null
+ && user.getUserId() != null
+ && Integer.valueOf(2).equals(user.getRoleType())
+ && user.getObjectId() != null;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/PartnerTypeRoleServiceTest.java b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/PartnerTypeRoleServiceTest.java
new file mode 100644
index 0000000..487f11c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/PartnerTypeRoleServiceTest.java
@@ -0,0 +1,140 @@
+package com.ruoyi.system.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.ruoyi.chargingPile.api.feignClient.SiteClient;
+import com.ruoyi.chargingPile.api.model.Partner;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.exception.ServiceException;
+import com.ruoyi.system.api.domain.SysRole;
+import com.ruoyi.system.api.domain.SysUser;
+import com.ruoyi.system.domain.SysUserRole;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class PartnerTypeRoleServiceTest {
+
+ @ParameterizedTest
+ @CsvSource({
+ "1, independent_partner, 11",
+ "2, site_owner, 12",
+ "3, service_provider, 13"
+ })
+ void addsRoleMatchingPartnerType(Integer partnerType, String expectedRoleKey, Long expectedRoleId) {
+ Fixture fixture = new Fixture(partnerType);
+ fixture.stubBuiltInRoles();
+ when(fixture.userRoleService.list(any(Wrapper.class))).thenReturn(Collections.emptyList());
+
+ fixture.service.synchronize(fixture.user);
+
+ ArgumentCaptor<SysUserRole> captor = ArgumentCaptor.forClass(SysUserRole.class);
+ verify(fixture.userRoleService).save(captor.capture());
+ assertEquals(expectedRoleId, captor.getValue().getRoleId());
+ assertEquals(expectedRoleKey, fixture.roleKey(expectedRoleId));
+ }
+
+ @Test
+ void replacesStaleBuiltInRoleButKeepsUnrelatedCustomRole() {
+ Fixture fixture = new Fixture(2);
+ fixture.stubBuiltInRoles();
+ SysUserRole oldTypeRole = userRole(100L, 11L);
+ SysUserRole customRole = userRole(100L, 99L);
+ when(fixture.userRoleService.list(any(Wrapper.class)))
+ .thenReturn(Arrays.asList(oldTypeRole, customRole));
+
+ fixture.service.synchronize(fixture.user);
+
+ verify(fixture.userRoleService).remove(any(Wrapper.class));
+ ArgumentCaptor<SysUserRole> captor = ArgumentCaptor.forClass(SysUserRole.class);
+ verify(fixture.userRoleService).save(captor.capture());
+ assertEquals(Long.valueOf(12L), captor.getValue().getRoleId());
+ }
+
+ @Test
+ void doesNothingForPlatformUser() {
+ Fixture fixture = new Fixture(1);
+ fixture.user.setRoleType(1);
+
+ fixture.service.synchronize(fixture.user);
+
+ verify(fixture.siteClient, never()).getPartnerR(any());
+ verify(fixture.roleService, never()).list(any(Wrapper.class));
+ verify(fixture.userRoleService, never()).save(any(SysUserRole.class));
+ }
+
+ @Test
+ void failsClearlyWhenConfiguredRoleIsMissing() {
+ Fixture fixture = new Fixture(3);
+ when(fixture.roleService.list(any(Wrapper.class)))
+ .thenReturn(Arrays.asList(role(11L, "independent_partner"), role(12L, "site_owner")));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> fixture.service.synchronize(fixture.user));
+
+ assertEquals("系统角色【service_provider】不存在或已停用,请先配置角色", exception.getMessage());
+ verify(fixture.userRoleService, never()).save(any(SysUserRole.class));
+ }
+
+ private static SysRole role(Long roleId, String roleKey) {
+ SysRole role = new SysRole();
+ role.setRoleId(roleId);
+ role.setRoleKey(roleKey);
+ return role;
+ }
+
+ private static SysUserRole userRole(Long userId, Long roleId) {
+ SysUserRole userRole = new SysUserRole();
+ userRole.setUserId(userId);
+ userRole.setRoleId(roleId);
+ return userRole;
+ }
+
+ private static class Fixture {
+ private final SiteClient siteClient = mock(SiteClient.class);
+ private final ISysRoleService roleService = mock(ISysRoleService.class);
+ private final ISysUserRoleService userRoleService = mock(ISysUserRoleService.class);
+ private final PartnerTypeRoleService service =
+ new PartnerTypeRoleService(siteClient, roleService, userRoleService);
+ private final SysUser user = new SysUser();
+
+ private Fixture(Integer partnerType) {
+ user.setUserId(100L);
+ user.setRoleType(2);
+ user.setObjectId(715);
+ Partner partner = new Partner();
+ partner.setId(715);
+ partner.setPartnerType(partnerType);
+ when(siteClient.getPartnerR(715)).thenReturn(R.ok(partner));
+ }
+
+ private void stubBuiltInRoles() {
+ when(roleService.list(any(Wrapper.class))).thenReturn(Arrays.asList(
+ role(11L, "independent_partner"),
+ role(12L, "site_owner"),
+ role(13L, "service_provider")
+ ));
+ }
+
+ private String roleKey(Long roleId) {
+ if (Long.valueOf(11L).equals(roleId)) {
+ return "independent_partner";
+ }
+ if (Long.valueOf(12L).equals(roleId)) {
+ return "site_owner";
+ }
+ return "service_provider";
+ }
+ }
+}
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java
index 435801d..6119b8c 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java
@@ -32,6 +32,12 @@
List<GetSiteListDTO> getSiteList(PageInfo<GetSiteListDTO> pageInfo, @Param("item") GetSiteList siteList, @Param("ids") Set<Integer> ids);
/**
+ * 获取下拉框使用的轻量站点列表。
+ */
+ List<GetSiteListDTO> getSiteOptions(@Param("ids") Set<Integer> ids,
+ @Param("partnerId") Integer partnerId);
+
+ /**
* 获取站点分页列表
* @return
*/
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java
index e53fd32..4950352 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java
@@ -369,36 +369,24 @@
@Override
public PageInfo<GetSiteListDTO> getSiteList1(Long userId) {
- GetSiteList siteList = new GetSiteList();
- siteList.setPageCurr(1);
- siteList.setPageSize(9999);
Set<Integer> ids = null;
- //校验合作商权限
SysUser sysUser = sysUserClient.getSysUser(userId).getData();
Integer roleType = sysUser.getRoleType();
- Integer objectId = sysUser.getObjectId();
- R<Integer> admin = sysUserClient.isAdmin(tokenService.getLoginUser().getUserid());
+ Integer partnerId = null;
- //合作商
if(roleType == 2){
- ids = partnerService.authSite(objectId, SiteMenu.SITE_LIST);
+ partnerId = sysUser.getObjectId();
}else{
- //非管理员需要根据角色和用户配置查询允许的站点数据
+ R<Integer> admin = sysUserClient.isAdmin(userId);
if(admin.getData()!=1){
ids = getAssignedSiteIds(sysUser.getUserId());
+ if (ids.isEmpty()) {
+ ids.add(-1);
+ }
}
}
- PageInfo<GetSiteListDTO> pageInfo = new PageInfo<>(siteList.getPageCurr(), siteList.getPageSize());
- List<GetSiteListDTO> list = this.baseMapper.getSiteList(pageInfo, siteList, ids);
- for (GetSiteListDTO getSiteListDTO : list) {
- Integer siteId = getSiteListDTO.getId();
- getSiteListDTO.setAuthAccountingStrategy(roleType == 1 ? true : partnerService.authMenu(objectId, siteId, SiteMenu.SITE_ACCOUNTING_STRATEGY));
- //平台账号才有此权限
- getSiteListDTO.setAuthPartner(roleType == 1 ? true : false);
- getSiteListDTO.setAuthUpdate(roleType == 1 ? true : partnerService.authMenu(objectId, siteId, SiteMenu.SITE_UPDATE));
- getSiteListDTO.setAuthDelete(roleType == 1 ? true : partnerService.authMenu(objectId, siteId, SiteMenu.SITE_DELETE));
- }
- return pageInfo.setRecords(list);
+ PageInfo<GetSiteListDTO> pageInfo = new PageInfo<>(1, 9999);
+ return pageInfo.setRecords(this.baseMapper.getSiteOptions(ids, partnerId));
}
private Set<Integer> getAssignedSiteIds(Long userId) {
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml b/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
index ae5fc07..28e17bc 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
@@ -128,6 +128,33 @@
order by a.sort desc, a.create_time desc
</select>
+ <select id="getSiteOptions" resultType="com.ruoyi.chargingPile.api.dto.GetSiteListDTO">
+ select a.id,
+ a.code,
+ a.name,
+ a.partner_id as partnerId,
+ b.partner_type as partnerType,
+ b.name as partnerName,
+ a.venue_partner_id as venuePartnerId,
+ vp.name as venuePartnerName,
+ a.site_type as siteType,
+ a.status
+ from t_site a
+ left join t_partner b on a.partner_id = b.id
+ left join t_partner vp on a.venue_partner_id = vp.id
+ where a.del_flag = 0
+ <if test="null != partnerId">
+ and (a.partner_id = #{partnerId} or a.venue_partner_id = #{partnerId})
+ </if>
+ <if test="null == partnerId and null != ids and ids.size() > 0">
+ and a.id in
+ <foreach collection="ids" item="siteId" open="(" separator="," close=")">
+ #{siteId}
+ </foreach>
+ </if>
+ order by a.sort desc, a.create_time desc
+ </select>
+
<select id="pageList" resultType="com.ruoyi.chargingPile.api.vo.SiteVO">
select
ts.id, ts.partner_id, ts.code, ts.`name`, ts.site_type, ts.business_category, ts.member_discount_flag as memberDiscountFlag, ts.status, ts.construction_site, ts.img_url,
diff --git a/ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/service/impl/SiteServiceImplTest.java b/ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/service/impl/SiteServiceImplTest.java
new file mode 100644
index 0000000..4c4ef7f
--- /dev/null
+++ b/ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/service/impl/SiteServiceImplTest.java
@@ -0,0 +1,49 @@
+package com.ruoyi.chargingPile.service.impl;
+
+import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
+import com.ruoyi.chargingPile.mapper.SiteMapper;
+import com.ruoyi.chargingPile.service.IPartnerService;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.system.api.domain.SysUser;
+import com.ruoyi.system.api.feignClient.SysUserClient;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Collections;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SiteServiceImplTest {
+
+ @Test
+ void partnerSiteListIncludesAllSitesRelatedToCurrentPartner() {
+ SiteServiceImpl service = new SiteServiceImpl();
+ SiteMapper mapper = mock(SiteMapper.class);
+ IPartnerService partnerService = mock(IPartnerService.class);
+ SysUserClient sysUserClient = mock(SysUserClient.class);
+ ReflectionTestUtils.setField(service, "baseMapper", mapper);
+ ReflectionTestUtils.setField(service, "partnerService", partnerService);
+ ReflectionTestUtils.setField(service, "sysUserClient", sysUserClient);
+
+ SysUser sysUser = new SysUser();
+ sysUser.setUserId(100L);
+ sysUser.setRoleType(2);
+ sysUser.setObjectId(715);
+
+ when(sysUserClient.getSysUser(100L)).thenReturn(R.ok(sysUser));
+ when(mapper.getSiteOptions(isNull(), eq(715)))
+ .thenReturn(Collections.<GetSiteListDTO>emptyList());
+
+ service.getSiteList1(100L);
+
+ verify(mapper).getSiteOptions(isNull(), eq(715));
+ verify(partnerService, never()).authSite(any(), any());
+ verify(sysUserClient, never()).isAdmin(any());
+ }
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
index a6d8839..54ead5a 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
@@ -279,6 +279,6 @@
* @param startTime
* @param endTime
*/
- List<Map<String, Object>> getAccountSettlementStatement(@Param("startTime") String startTime, @Param("endTime") String endTime,
- @Param("rechargePaymentType") Integer rechargePaymentType);
+ List<Map<String, Object>> getAccountSettlementStatement(@Param("startTime") String startTime,
+ @Param("endTime") String endTime);
}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
index 58221c3..c06525b 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
@@ -447,7 +447,7 @@
* @param endTime
* @return
*/
- List<Map<String, Object>> getAccountSettlementStatement(String startTime, String endTime, Integer rechargePaymentType);
+ List<Map<String, Object>> getAccountSettlementStatement(String startTime, String endTime);
/**
* 手动处理退款数据
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
index d611237..df83cbc 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -7206,8 +7206,8 @@
* @return
*/
@Override
- public List<Map<String, Object>> getAccountSettlementStatement(String startTime, String endTime, Integer rechargePaymentType) {
- return this.baseMapper.getAccountSettlementStatement(startTime, endTime, rechargePaymentType);
+ public List<Map<String, Object>> getAccountSettlementStatement(String startTime, String endTime) {
+ return this.baseMapper.getAccountSettlementStatement(startTime, endTime);
}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java
index 5077b98..4e96a5f 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java
@@ -279,7 +279,7 @@
@Scheduled(fixedRate = 1000 * 60)
public void taskOneMinutes() {
- if(null != port && port == 5400){
+ if (isScheduledTaskPort(port)) {
List<TChargingOrder> upStatusChargingOrder = chargingOrderService.findUpStatusChargingOrder();
log.info("定时任务执行,查询需要手动修改状态的订单数量:{}", upStatusChargingOrder.size());
for (TChargingOrder order : upStatusChargingOrder) {
@@ -297,7 +297,7 @@
//十分钟循环执行的定时任务
@Scheduled(fixedRate = 1000 * 60 * 10)
public void taskTenMinutes() {
- if(null != port && port == 5400){
+ if (isScheduledTaskPort(port)) {
List<TChargingOrder> failedStartupOrder = chargingOrderService.findFailedStartupOrder();
log.info("定时任务执行,查询到启动失败的订单数量:{}", failedStartupOrder.size());
for (TChargingOrder order : failedStartupOrder) {
@@ -424,7 +424,7 @@
//定时任务添加结算账单汇总数据
@Scheduled(cron = "0 30 0 * * ?")
public void taskMonth() {
- if(null != port && port == 5400){
+ if (isScheduledTaskPort(port)) {
//推送三方引流平台数据
pushOrderDrainagePlatform();
//添加充电算账单汇总数据
@@ -437,7 +437,7 @@
// 每个月最后一天23点执行的定时任务
@Scheduled(cron = "0 0 23 * * ?")
public void taskLastDay() {
- if(null != port && port == 5400){
+ if (isScheduledTaskPort(port)) {
try {
int dayOfMonth = LocalDate.now().getDayOfMonth();
int lastDayOfMonth = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
@@ -460,6 +460,10 @@
public void onApplicationEvent(WebServerInitializedEvent event) {
port = event.getWebServer().getPort();
System.out.println("端口号:" + port);
+ }
+
+ static boolean isScheduledTaskPort(Integer serverPort) {
+ return Integer.valueOf(5400).equals(serverPort) || Integer.valueOf(9400).equals(serverPort);
}
@@ -1161,7 +1165,7 @@
accountSettlementStatement.setCode("JSD"+string+randomDigits);
//根据业务订单查询汇总数据
- List<Map<String, Object>> mapList = chargingOrderService.getAccountSettlementStatement(startTime, endTime, i);
+ List<Map<String, Object>> mapList = chargingOrderService.getAccountSettlementStatement(startTime, endTime);
BigDecimal rechargeAmount = BigDecimal.ZERO;
BigDecimal refundAmount = BigDecimal.ZERO;
BigDecimal platformFee = BigDecimal.ZERO;
diff --git a/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml b/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
index 5209388..bba3673 100644
--- a/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
+++ b/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -2710,33 +2710,47 @@
<select id="getAccountSettlementStatement" resultType="map">
- select
- aa.site_id as siteId,
- sum(aa.recharge_amount) as rechargeAmount,
- sum(aa.refund_amount) as refundAmount,
- sum(aa.serviceAmount) as serviceAmount
- from (
- select
- b.id as orderId,
- b.site_id,
- ifnull(b.payment_amount, 0) as recharge_amount,
- ifnull(c.refund_amount, 0) as refund_amount,
- sum(ifnull(a.period_service_price, 0)) as serviceAmount
- from t_charging_order_accounting_strategy a
- left join t_charging_order b on (a.charging_order_id = b.id)
- left join (
- select charging_order_id, sum(ifnull(refund_amount, 0)) as refund_amount
- from t_charging_order_refund
- where refund_status = 2
- group by charging_order_id
- ) c on b.id = c.charging_order_id
- where b.`status` = 5
- and b.del_flag = 0
- and b.order_source = 1
- and b.source_name = 'ICBC'
- and b.start_time between #{startTime} and #{endTime}
- group by orderId, site_id, recharge_amount, refund_amount
- ) as aa group by aa.site_id order by aa.site_id
+ SELECT
+ b.site_id AS siteId,
+ SUM(CASE
+ WHEN sr.charging_order_id IS NOT NULL THEN sr.paid_amount
+ ELSE IFNULL(b.payment_amount, 0)
+ END) AS rechargeAmount,
+ SUM(IFNULL(r.refund_amount, 0)) AS refundAmount,
+ SUM(CASE
+ WHEN sr.charging_order_id IS NOT NULL THEN sr.paid_service_amount
+ ELSE IFNULL(a.service_amount, 0)
+ END) AS serviceAmount
+ FROM t_charging_order b
+ LEFT JOIN (
+ SELECT charging_order_id,
+ SUM(IFNULL(period_service_price, 0)) AS service_amount
+ FROM t_charging_order_accounting_strategy
+ GROUP BY charging_order_id
+ ) a ON a.charging_order_id = b.id
+ LEFT JOIN (
+ SELECT charging_order_id,
+ SUM(IFNULL(channel_pay_amount, 0)) AS paid_amount,
+ SUM(IFNULL(channel_service_amount, 0)) AS paid_service_amount
+ FROM t_charging_order_share_record
+ WHERE pay_channel = 'ICBC'
+ AND del_flag = 0
+ GROUP BY charging_order_id
+ ) sr ON sr.charging_order_id = b.id
+ LEFT JOIN (
+ SELECT charging_order_id,
+ SUM(IFNULL(refund_amount, 0)) AS refund_amount
+ FROM t_charging_order_refund
+ WHERE refund_status = 2
+ GROUP BY charging_order_id
+ ) r ON r.charging_order_id = b.id
+ WHERE b.status = 5
+ AND b.del_flag = 0
+ AND b.order_source = 1
+ AND b.source_name = 'ICBC'
+ AND b.start_time BETWEEN #{startTime} AND #{endTime}
+ GROUP BY b.site_id
+ ORDER BY b.site_id
</select>
<sql id="enterpriseChargingBaseWhere">
diff --git a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/AccountSettlementStatementMapperTest.java b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/AccountSettlementStatementMapperTest.java
new file mode 100644
index 0000000..aeb8bf6
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/AccountSettlementStatementMapperTest.java
@@ -0,0 +1,45 @@
+package com.ruoyi.order.mapper;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class AccountSettlementStatementMapperTest {
+
+ @Test
+ void usesIcbcPaidAmountsAndKeepsLegacyFieldsForCompatibility() throws IOException {
+ String statementMapper = resource("mapper/order/TAccountSettlementStatementMapper.xml");
+ assertTrue(statementMapper.contains("AND account_type = 3"));
+ assertTrue(statementMapper.contains("SUM(platform_income)"));
+ assertTrue(statementMapper.contains("SUM(partner_income)"));
+ assertTrue(statementMapper.contains("platform_fee"));
+ assertTrue(statementMapper.contains("tripartite_commission"));
+ assertTrue(statementMapper.contains("recorded_amount"));
+
+ String orderMapper = resource("mapper/order/TChargingOrderMapper.xml");
+ String settlementQuery = orderMapper.substring(
+ orderMapper.indexOf("<select id=\"getAccountSettlementStatement\""),
+ orderMapper.indexOf("<sql id=\"enterpriseChargingBaseWhere\""));
+ assertTrue(settlementQuery.contains("b.order_source = 1"));
+ assertTrue(settlementQuery.contains("b.source_name = 'ICBC'"));
+ assertTrue(settlementQuery.contains("pay_channel = 'ICBC'"));
+ assertTrue(settlementQuery.contains("channel_pay_amount"));
+ assertTrue(settlementQuery.contains("channel_service_amount"));
+ }
+
+ private String resource(String path) throws IOException {
+ InputStream input = getClass().getClassLoader().getResourceAsStream(path);
+ assertNotNull(input);
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
+ return reader.lines().collect(Collectors.joining("\n"));
+ }
+ }
+}
diff --git a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/util/task/AccountSettlementIncomeTest.java b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/util/task/AccountSettlementIncomeTest.java
index 24424a4..fa5bc01 100644
--- a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/util/task/AccountSettlementIncomeTest.java
+++ b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/util/task/AccountSettlementIncomeTest.java
@@ -9,6 +9,14 @@
class AccountSettlementIncomeTest {
@Test
+ void enablesScheduledTasksOnLegacyAndOrderPorts() {
+ assertEquals(true, TaskUtil.isScheduledTaskPort(5400));
+ assertEquals(true, TaskUtil.isScheduledTaskPort(9400));
+ assertEquals(false, TaskUtil.isScheduledTaskPort(9500));
+ assertEquals(false, TaskUtil.isScheduledTaskPort(null));
+ }
+
+ @Test
void calculatesPartnerAndPlatformIncomeForMiniProgramOrder() {
BigDecimal partnerIncome = TaskUtil.calculateAccountPartnerIncome(
new BigDecimal("10.00"), new BigDecimal("30"), false);
diff --git a/sql/20260728_account_settlement_v2.sql b/sql/20260728_account_settlement_v2.sql
index bfa7cb7..7c874d4 100644
--- a/sql/20260728_account_settlement_v2.sql
+++ b/sql/20260728_account_settlement_v2.sql
@@ -1,4 +1,3 @@
ALTER TABLE `t_account_settlement_statement`
ADD COLUMN `platform_income` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '平台收入' AFTER `recorded_amount`,
ADD COLUMN `partner_income` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '合作商收入' AFTER `platform_income`;
-
--
Gitblit v1.7.1