From 3080d55319ab40fe99064aa4689dbe0c38301e9d Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期五, 31 七月 2026 18:49:55 +0800
Subject: [PATCH] 修改管理后台 1、修改退款后没有重新添加新的分账记录
---
ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/service/impl/SiteServiceImplTest.java | 146 +++++++++++++++++++++++++++++++++++-
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java | 3
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java | 20 ++++-
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java | 60 ++++++++++-----
4 files changed, 198 insertions(+), 31 deletions(-)
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java
index 7951a95..3f5c578 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java
@@ -398,11 +398,17 @@
@ApiOperation(tags = {"后台-计费策略"},value = "删除计费策略")
@DeleteMapping(value = "/deleteById")
public AjaxResult<Boolean> deleteById(@RequestParam("id") Integer id) {
- // 判断策略是否在使用
+ // 判断策略是否被站点使用
long count = siteService.count(Wrappers.lambdaQuery(Site.class)
.eq(Site::getAccountingStrategyId, id));
if(count>0){
- return AjaxResult.error("该计费策略正在使用中,无法删除");
+ return AjaxResult.error("该计费策略正在被站点使用,无法删除");
+ }
+ // 判断策略是否被充电枪使用
+ long gunCount = chargingGunService.count(Wrappers.lambdaQuery(TChargingGun.class)
+ .eq(TChargingGun::getAccountingStrategyId, id));
+ if(gunCount>0){
+ return AjaxResult.error("该计费策略正在被充电枪使用,无法删除");
}
// 刪除计费策略明细信息
accountingStrategyDetailService.remove(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
@@ -419,11 +425,17 @@
@DeleteMapping(value = "/deleteByIds")
public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
String[] split = ids.split(",");
- // 判断策略是否在使用
+ // 判断策略是否被站点使用
long count = siteService.count(Wrappers.lambdaQuery(Site.class)
.in(Site::getAccountingStrategyId, Arrays.asList(split)));
if(count>0){
- return AjaxResult.error("该计费策略正在使用中,无法删除");
+ return AjaxResult.error("该计费策略正在被站点使用,无法删除");
+ }
+ // 判断策略是否被充电枪使用
+ long gunCount = chargingGunService.count(Wrappers.lambdaQuery(TChargingGun.class)
+ .in(TChargingGun::getAccountingStrategyId, Arrays.asList(split)));
+ if(gunCount>0){
+ return AjaxResult.error("该计费策略正在被充电枪使用,无法删除");
}
// 刪除计费策略明细信息
accountingStrategyDetailService.remove(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
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 a4f0d43..3af2da3 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
@@ -958,29 +958,49 @@
@Override
@Transactional(rollbackFor = Exception.class)
public void setAccountingStrategy(Integer id, Integer accountingStrategyId) {
- Site site = this.getById(id);
- site.setAccountingStrategyId(accountingStrategyId);
- this.updateById(site);
- List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getSiteId, id).eq(TChargingGun::getDelFlag, 0));
- for (TChargingGun tChargingGun : list) {
- TChargingGun tChargingGun1 = new TChargingGun();
- tChargingGun1.setId(tChargingGun.getId());
- tChargingGun1.setAccountingStrategyId(accountingStrategyId);
- chargingGunService.updateById(tChargingGun1);
- }
+ // 只更新计费策略字段,避免 updateById 全字段更新导致 SQL 过长
+ this.lambdaUpdate()
+ .eq(Site::getId, id)
+ .set(Site::getAccountingStrategyId, accountingStrategyId)
+ .update();
+ chargingGunService.lambdaUpdate()
+ .eq(TChargingGun::getSiteId, id)
+ .eq(TChargingGun::getDelFlag, 0)
+ .set(TChargingGun::getAccountingStrategyId, accountingStrategyId)
+ .update();
- //下发硬件数据
+ //下发硬件数据 - 异步执行,避免事务长时间占用数据库连接导致 Communications link failure
List<TAccountingStrategyDetail> accountingStrategyDetails = accountingStrategyDetailService.list(new LambdaQueryWrapper<TAccountingStrategyDetail>().eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategyId));
- List<TChargingPile> list1 = chargingPileService.lambdaQuery().eq(TChargingPile::getSiteId, id).eq(TChargingPile::getDelFlag, 0).list();
- for (TChargingPile tChargingPile : list1) {
- integrationClient.setupBillingModel1(tChargingPile.getCode(), JSON.toJSONString(accountingStrategyDetails));
- chengDuJianGuanClient.notificationStationFee(tChargingPile.getId());
- }
+ List<TChargingPile> chargingPiles = chargingPileService.lambdaQuery().eq(TChargingPile::getSiteId, id).eq(TChargingPile::getDelFlag, 0).list();
+ Site site = this.lambdaQuery()
+ .select(Site::getId, Site::getIsOpenSynchronization)
+ .eq(Site::getId, id)
+ .one();
+ boolean needSync = site != null && site.getIsOpenSynchronization() != null && site.getIsOpenSynchronization() == 1;
- if(1 == site.getIsOpenSynchronization()){
- //推送三方平台
- tcecClient.notificationStationChange(Arrays.asList(id));
- }
+ new Thread(() -> {
+ for (TChargingPile tChargingPile : chargingPiles) {
+ try {
+ integrationClient.setupBillingModel1(tChargingPile.getCode(), JSON.toJSONString(accountingStrategyDetails));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ chengDuJianGuanClient.notificationStationFee(tChargingPile.getId());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (needSync) {
+ //推送三方平台
+ try {
+ tcecClient.notificationStationChange(Arrays.asList(id));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }).start();
}
@Override
@Transactional(rollbackFor = Exception.class)
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
index 4c4ef7f..d333b88 100644
--- 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
@@ -1,33 +1,76 @@
package com.ruoyi.chargingPile.service.impl;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
+import com.ruoyi.chargingPile.api.model.Site;
+import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
+import com.ruoyi.chargingPile.api.model.TChargingGun;
+import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.mapper.SiteMapper;
import com.ruoyi.chargingPile.service.IPartnerService;
+import com.ruoyi.chargingPile.service.ITAccountingStrategyDetailService;
+import com.ruoyi.chargingPile.service.ITChargingGunService;
+import com.ruoyi.chargingPile.service.ITChargingPileService;
import com.ruoyi.common.core.domain.R;
+import com.ruoyi.integration.api.feignClient.ChengDuJianGuanClient;
+import com.ruoyi.integration.api.feignClient.IntegrationClient;
+import com.ruoyi.integration.api.feignClient.TcecClient;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class SiteServiceImplTest {
+ private SiteServiceImpl service;
+ private SiteMapper siteMapper;
+ private ITChargingGunService chargingGunService;
+ private ITAccountingStrategyDetailService accountingStrategyDetailService;
+ private ITChargingPileService chargingPileService;
+ private IntegrationClient integrationClient;
+ private ChengDuJianGuanClient chengDuJianGuanClient;
+ private TcecClient tcecClient;
+
+ @BeforeEach
+ void setUp() {
+ service = new SiteServiceImpl();
+ siteMapper = mock(SiteMapper.class);
+ chargingGunService = mock(ITChargingGunService.class);
+ accountingStrategyDetailService = mock(ITAccountingStrategyDetailService.class);
+ chargingPileService = mock(ITChargingPileService.class);
+ integrationClient = mock(IntegrationClient.class);
+ chengDuJianGuanClient = mock(ChengDuJianGuanClient.class);
+ tcecClient = mock(TcecClient.class);
+
+ ReflectionTestUtils.setField(service, "baseMapper", siteMapper);
+ ReflectionTestUtils.setField(service, "chargingGunService", chargingGunService);
+ ReflectionTestUtils.setField(service, "accountingStrategyDetailService", accountingStrategyDetailService);
+ ReflectionTestUtils.setField(service, "chargingPileService", chargingPileService);
+ ReflectionTestUtils.setField(service, "integrationClient", integrationClient);
+ ReflectionTestUtils.setField(service, "chengDuJianGuanClient", chengDuJianGuanClient);
+ ReflectionTestUtils.setField(service, "tcecClient", tcecClient);
+ }
+
@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);
@@ -37,13 +80,106 @@
sysUser.setObjectId(715);
when(sysUserClient.getSysUser(100L)).thenReturn(R.ok(sysUser));
- when(mapper.getSiteOptions(isNull(), eq(715)))
+ when(siteMapper.getSiteOptions(isNull(), eq(715)))
.thenReturn(Collections.<GetSiteListDTO>emptyList());
service.getSiteList1(100L);
- verify(mapper).getSiteOptions(isNull(), eq(715));
+ verify(siteMapper).getSiteOptions(isNull(), eq(715));
verify(partnerService, never()).authSite(any(), any());
verify(sysUserClient, never()).isAdmin(any());
}
+
+ /**
+ * 验证 setAccountingStrategy 使用 lambdaUpdate 只更新 accountingStrategyId 字段,
+ * 并且远程调用在异步线程中执行,避免事务长时间占用数据库连接
+ */
+ @Test
+ void setAccountingStrategyUpdatesOnlyTargetFieldAndAsyncRemoteCalls() throws Exception {
+ Integer siteId = 1;
+ Integer accountingStrategyId = 100;
+
+ // mock 充电枪列表
+ List<TChargingGun> guns = new ArrayList<>();
+ TChargingGun gun = new TChargingGun();
+ gun.setId(10);
+ gun.setSiteId(siteId);
+ guns.add(gun);
+
+ // mock 充电桩列表
+ List<TChargingPile> piles = new ArrayList<>();
+ TChargingPile pile = new TChargingPile();
+ pile.setCode("PILE001");
+ pile.setId(200);
+ pile.setSiteId(siteId);
+ piles.add(pile);
+
+ // mock 计费策略明细
+ List<TAccountingStrategyDetail> details = new ArrayList<>();
+
+ // mock Site 查询(用于 isOpenSynchronization)
+ Site mockSite = new Site();
+ mockSite.setId(siteId);
+ mockSite.setIsOpenSynchronization(1);
+
+ when(siteMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(Collections.singletonList(mockSite));
+ when(chargingGunService.list(any(LambdaQueryWrapper.class))).thenReturn(guns);
+ when(accountingStrategyDetailService.list(any(LambdaQueryWrapper.class))).thenReturn(details);
+
+ assertDoesNotThrow(() -> service.setAccountingStrategy(siteId, accountingStrategyId));
+
+ // 验证数据库操作:站点和充电枪都通过 lambdaUpdate 更新
+ verify(siteMapper, atLeastOnce()).update(any(), any());
+ verify(siteMapper).selectList(any(LambdaQueryWrapper.class));
+
+ // 异步线程执行需要等待一小段时间
+ Thread.sleep(500);
+
+ // 验证远程调用在异步线程中执行
+ verify(integrationClient, timeout(1000)).setupBillingModel1(eq("PILE001"), any());
+ verify(chengDuJianGuanClient, timeout(1000)).notificationStationFee(eq(200));
+ verify(tcecClient, timeout(1000)).notificationStationChange(any());
+ }
+
+ /**
+ * 验证 setAccountingStrategy 在站点无需同步时不会调用三方平台推送
+ */
+ @Test
+ void setAccountingStrategySkipsSyncWhenNotOpen() throws Exception {
+ Integer siteId = 2;
+ Integer accountingStrategyId = 200;
+
+ // mock 充电枪列表
+ TChargingGun gun = new TChargingGun();
+ gun.setId(20);
+ gun.setSiteId(siteId);
+ List<TChargingGun> guns = Collections.singletonList(gun);
+
+ // mock 充电桩列表
+ TChargingPile pile = new TChargingPile();
+ pile.setCode("PILE002");
+ pile.setId(201);
+ pile.setSiteId(siteId);
+ List<TChargingPile> piles = Collections.singletonList(pile);
+
+ List<TAccountingStrategyDetail> details = new ArrayList<>();
+
+ // isOpenSynchronization = 0,不需要同步
+ Site mockSite = new Site();
+ mockSite.setId(siteId);
+ mockSite.setIsOpenSynchronization(0);
+
+ when(siteMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(Collections.singletonList(mockSite));
+ when(chargingGunService.list(any(LambdaQueryWrapper.class))).thenReturn(guns);
+ when(accountingStrategyDetailService.list(any(LambdaQueryWrapper.class))).thenReturn(details);
+
+ assertDoesNotThrow(() -> service.setAccountingStrategy(siteId, accountingStrategyId));
+
+ Thread.sleep(500);
+
+ verify(integrationClient, timeout(1000)).setupBillingModel1(eq("PILE002"), any());
+ verify(chengDuJianGuanClient, timeout(1000)).notificationStationFee(eq(201));
+ // tcecClient.notificationStationChange 不应被调用
+ verify(tcecClient, never()).notificationStationChange(any());
+ }
}
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 840aeda..9dfa2a4 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
@@ -8022,9 +8022,8 @@
private boolean isNeedChargingOrderShare(TChargingOrder chargingOrder) {
return chargingOrder != null
- && Integer.valueOf(5).equals(chargingOrder.getStatus())
&& Integer.valueOf(2).equals(chargingOrder.getRechargePaymentStatus())
- && Integer.valueOf(2).equals(chargingOrder.getRefundStatus())
+ && (Integer.valueOf(2).equals(chargingOrder.getRefundStatus()) || Integer.valueOf(5).equals(chargingOrder.getStatus()))
&& getChargingOrderShareBaseAmount(chargingOrder).compareTo(BigDecimal.ZERO) > 0;
}
--
Gitblit v1.7.1