mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-19 18:45:03 +08:00
对接jcpp
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
package com.jsowell.web.controller.jcpp;
|
||||
|
||||
import com.jsowell.common.core.controller.BaseController;
|
||||
import com.jsowell.common.core.domain.AjaxResult;
|
||||
import com.jsowell.pile.domain.PileBasicInfo;
|
||||
import com.jsowell.pile.domain.PileBillingTemplate;
|
||||
import com.jsowell.pile.jcpp.dto.JcppPricingModel;
|
||||
import com.jsowell.pile.jcpp.util.PricingModelConverter;
|
||||
import com.jsowell.pile.service.PileBasicInfoService;
|
||||
import com.jsowell.pile.service.PileBillingTemplateService;
|
||||
import com.jsowell.pile.vo.web.BillingTemplateVO;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JCPP 计费模板接口
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
// @Slf4j
|
||||
@Api(tags = "JCPP计费模板接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/jcpp")
|
||||
public class JcppBillingController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private PileBasicInfoService pileBasicInfoService;
|
||||
|
||||
@Autowired
|
||||
private PileBillingTemplateService pileBillingTemplateService;
|
||||
|
||||
/**
|
||||
* 获取充电桩计费模板
|
||||
*
|
||||
* @param pileCode 充电桩编码
|
||||
* @return 计费模板
|
||||
*/
|
||||
@ApiOperation("获取充电桩计费模板")
|
||||
@GetMapping("/billing/{pileCode}")
|
||||
public AjaxResult getBillingTemplate(
|
||||
@ApiParam(value = "充电桩编码", required = true) @PathVariable String pileCode) {
|
||||
try {
|
||||
logger.info("查询充电桩计费模板: pileCode={}", pileCode);
|
||||
|
||||
// 1. 根据 pileCode 查询充电桩
|
||||
PileBasicInfo pileInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileCode);
|
||||
if (pileInfo == null) {
|
||||
logger.warn("充电桩不存在: pileCode={}", pileCode);
|
||||
return AjaxResult.error(404, "充电桩不存在");
|
||||
}
|
||||
|
||||
// 2. 获取关联的计费模板 ID
|
||||
BillingTemplateVO billingTemplateVO = pileBillingTemplateService.selectBillingTemplateDetailByPileSn(pileCode);
|
||||
if (billingTemplateVO == null || billingTemplateVO.getTemplateId() == null) {
|
||||
logger.warn("充电桩未配置计费模板: pileCode={}", pileCode);
|
||||
return AjaxResult.error(404, "未配置计费模板");
|
||||
}
|
||||
Long billingTemplateId = Long.parseLong(billingTemplateVO.getTemplateId());
|
||||
|
||||
// 3. 查询计费模板
|
||||
PileBillingTemplate template = pileBillingTemplateService.selectPileBillingTemplateById(billingTemplateId);
|
||||
if (template == null) {
|
||||
logger.warn("计费模板不存在: pileCode={}, billingTemplateId={}", pileCode, billingTemplateId);
|
||||
return AjaxResult.error(404, "计费模板不存在");
|
||||
}
|
||||
|
||||
// 4. 转换为 JCPP 格式
|
||||
JcppPricingModel pricingModel = PricingModelConverter.convert(template);
|
||||
|
||||
// 5. 构建返回结果
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("pricingId", billingTemplateId);
|
||||
data.put("pricingModel", pricingModel);
|
||||
|
||||
logger.info("查询计费模板成功: pileCode={}, pricingId={}", pileCode, billingTemplateId);
|
||||
return AjaxResult.success(data);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询计费模板异常: pileCode={}", pileCode, e);
|
||||
return AjaxResult.error("查询计费模板失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据计费模板ID获取计费模板
|
||||
*
|
||||
* @param pricingId 计费模板ID
|
||||
* @return 计费模板
|
||||
*/
|
||||
@ApiOperation("根据ID获取计费模板")
|
||||
@GetMapping("/billing/id/{pricingId}")
|
||||
public AjaxResult getBillingTemplateById(
|
||||
@ApiParam(value = "计费模板ID", required = true) @PathVariable Long pricingId) {
|
||||
try {
|
||||
logger.info("查询计费模板: pricingId={}", pricingId);
|
||||
|
||||
// 查询计费模板
|
||||
PileBillingTemplate template = pileBillingTemplateService.selectPileBillingTemplateById(pricingId);
|
||||
if (template == null) {
|
||||
logger.warn("计费模板不存在: pricingId={}", pricingId);
|
||||
return AjaxResult.error(404, "计费模板不存在");
|
||||
}
|
||||
|
||||
// 转换为 JCPP 格式
|
||||
JcppPricingModel pricingModel = PricingModelConverter.convert(template);
|
||||
|
||||
// 构建返回结果
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("pricingId", pricingId);
|
||||
data.put("pricingModel", pricingModel);
|
||||
|
||||
logger.info("查询计费模板成功: pricingId={}", pricingId);
|
||||
return AjaxResult.success(data);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询计费模板异常: pricingId={}", pricingId, e);
|
||||
return AjaxResult.error("查询计费模板失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.jsowell.web.controller.jcpp;
|
||||
|
||||
import com.jsowell.common.core.controller.BaseController;
|
||||
import com.jsowell.pile.jcpp.config.JcppConfig;
|
||||
import com.jsowell.pile.jcpp.dto.JcppUplinkMessage;
|
||||
import com.jsowell.pile.jcpp.dto.JcppUplinkResponse;
|
||||
import com.jsowell.pile.jcpp.service.IJcppMessageService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* JCPP 消息接收 Controller
|
||||
* 用于接收 JCPP 项目推送的充电桩上行消息
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
// @Slf4j
|
||||
@Api(tags = "JCPP消息接收接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/jcpp")
|
||||
public class JcppMessageController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IJcppMessageService jcppMessageService;
|
||||
|
||||
@Autowired
|
||||
private JcppConfig jcppConfig;
|
||||
|
||||
/**
|
||||
* 接收 JCPP 上行消息
|
||||
*
|
||||
* @param message 上行消息
|
||||
* @return 响应
|
||||
*/
|
||||
@ApiOperation("接收JCPP上行消息")
|
||||
@PostMapping("/uplink")
|
||||
public JcppUplinkResponse receiveUplink(@RequestBody JcppUplinkMessage message) {
|
||||
// 检查是否启用 JCPP 对接
|
||||
if (!jcppConfig.isEnabled()) {
|
||||
logger.warn("JCPP 对接未启用,忽略消息: {}", message.getMessageId());
|
||||
return JcppUplinkResponse.error(message.getMessageId(), "JCPP 对接未启用");
|
||||
}
|
||||
|
||||
logger.info("收到 JCPP 上行消息: messageId={}, messageType={}, pileCode={}, sessionId={}",
|
||||
message.getMessageId(), message.getMessageType(),
|
||||
message.getPileCode(), message.getSessionId());
|
||||
|
||||
try {
|
||||
return jcppMessageService.handleMessage(message);
|
||||
} catch (Exception e) {
|
||||
logger.error("处理 JCPP 上行消息异常: messageId={}, error={}",
|
||||
message.getMessageId(), e.getMessage(), e);
|
||||
return JcppUplinkResponse.error(message.getMessageId(), "处理消息异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.jsowell.web.controller.jcpp;
|
||||
|
||||
import com.jsowell.common.core.controller.BaseController;
|
||||
import com.jsowell.common.core.domain.AjaxResult;
|
||||
import com.jsowell.pile.jcpp.service.IJcppRemoteChargeService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
// import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* JCPP 远程充电 Controller
|
||||
* 用于 APP/小程序发起的远程启动/停止充电
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
// @Slf4j
|
||||
@Api(tags = "JCPP远程充电接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/jcpp/charge")
|
||||
public class JcppRemoteChargeController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IJcppRemoteChargeService jcppRemoteChargeService;
|
||||
|
||||
/**
|
||||
* 远程启动充电
|
||||
*/
|
||||
@ApiOperation("远程启动充电")
|
||||
@PostMapping("/start")
|
||||
public AjaxResult startCharging(
|
||||
@ApiParam(value = "会员ID", required = true) @RequestParam String memberId,
|
||||
@ApiParam(value = "充电桩编码", required = true) @RequestParam String pileCode,
|
||||
@ApiParam(value = "枪编号", required = true) @RequestParam String gunNo,
|
||||
@ApiParam(value = "预付金额(元)", required = true) @RequestParam String payAmount) {
|
||||
try {
|
||||
String orderCode = jcppRemoteChargeService.remoteStartCharging(memberId, pileCode, gunNo, payAmount);
|
||||
return AjaxResult.success("启动指令已发送", orderCode);
|
||||
} catch (Exception e) {
|
||||
logger.error("远程启动充电失败, memberId: {}, pileCode: {}, error: {}",
|
||||
memberId, pileCode, e.getMessage(), e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程停止充电
|
||||
*/
|
||||
@ApiOperation("远程停止充电")
|
||||
@PostMapping("/stop")
|
||||
public AjaxResult stopCharging(
|
||||
@ApiParam(value = "会员ID", required = true) @RequestParam String memberId,
|
||||
@ApiParam(value = "订单号", required = true) @RequestParam String orderCode) {
|
||||
try {
|
||||
boolean result = jcppRemoteChargeService.remoteStopCharging(memberId, orderCode);
|
||||
if (result) {
|
||||
return AjaxResult.success("停止指令已发送");
|
||||
} else {
|
||||
return AjaxResult.error("停止充电失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("远程停止充电失败, memberId: {}, orderCode: {}, error: {}",
|
||||
memberId, orderCode, e.getMessage(), e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查充电桩是否在线
|
||||
*/
|
||||
@ApiOperation("检查充电桩是否在线")
|
||||
@GetMapping("/online/{pileCode}")
|
||||
public AjaxResult checkOnline(
|
||||
@ApiParam(value = "充电桩编码", required = true) @PathVariable String pileCode) {
|
||||
try {
|
||||
boolean online = jcppRemoteChargeService.isPileOnline(pileCode);
|
||||
return AjaxResult.success(online);
|
||||
} catch (Exception e) {
|
||||
logger.error("检查充电桩在线状态失败, pileCode: {}, error: {}", pileCode, e.getMessage(), e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package com.jsowell.jcpp;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.jsowell.pile.jcpp.dto.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* JCPP 消息接收接口测试
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
public class JcppMessageControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
/**
|
||||
* 测试登录消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleLogin() throws Exception {
|
||||
// 构造登录消息
|
||||
JcppLoginData loginData = JcppLoginData.builder()
|
||||
.pileCode("TEST001")
|
||||
.credential("test-credential")
|
||||
.remoteAddress("192.168.1.100:8080")
|
||||
.nodeId("node-1")
|
||||
.nodeHostAddress("192.168.1.1")
|
||||
.nodeRestPort(8080)
|
||||
.nodeGrpcPort(9090)
|
||||
.build();
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-001")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("LOGIN")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(loginData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试心跳消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleHeartbeat() throws Exception {
|
||||
Map<String, Object> heartbeatData = new HashMap<>();
|
||||
heartbeatData.put("pileCode", "TEST001");
|
||||
heartbeatData.put("remoteAddress", "192.168.1.100:8080");
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-002")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("HEARTBEAT")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(heartbeatData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试查询计费模板消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleQueryPricing() throws Exception {
|
||||
Map<String, Object> queryData = new HashMap<>();
|
||||
queryData.put("pileCode", "TEST001");
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-003")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("QUERY_PRICING")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(queryData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试刷卡启动充电消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleStartCharge() throws Exception {
|
||||
JcppStartChargeData startData = JcppStartChargeData.builder()
|
||||
.pileCode("TEST001")
|
||||
.gunNo("1")
|
||||
.startType("CARD")
|
||||
.cardNo("1234567890")
|
||||
.needPassword(false)
|
||||
.build();
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-004")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("START_CHARGE")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(startData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试实时数据消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleRealTimeData() throws Exception {
|
||||
JcppRealTimeData realTimeData = JcppRealTimeData.builder()
|
||||
.pileCode("TEST001")
|
||||
.gunNo("1")
|
||||
.tradeNo("trade-001")
|
||||
.outputVoltage("380.5")
|
||||
.outputCurrent("32.0")
|
||||
.soc(50)
|
||||
.totalChargingDurationMin(30)
|
||||
.totalChargingEnergyKWh("15.5")
|
||||
.totalChargingCostYuan("12.40")
|
||||
.build();
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-005")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("REAL_TIME_DATA")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(realTimeData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试交易记录消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleTransactionRecord() throws Exception {
|
||||
JcppTransactionData transactionData = JcppTransactionData.builder()
|
||||
.pileCode("TEST001")
|
||||
.gunNo("1")
|
||||
.tradeNo("trade-001")
|
||||
.startTs(System.currentTimeMillis() - 3600000)
|
||||
.endTs(System.currentTimeMillis())
|
||||
.totalEnergyKWh("30.5")
|
||||
.totalAmountYuan("24.40")
|
||||
.tradeTs(System.currentTimeMillis())
|
||||
.stopReason("USER_STOP")
|
||||
.build();
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-006")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("TRANSACTION_RECORD")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(transactionData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试远程启动结果消息处理
|
||||
*/
|
||||
@Test
|
||||
public void testHandleRemoteStartResult() throws Exception {
|
||||
JcppRemoteStartResultData resultData = JcppRemoteStartResultData.builder()
|
||||
.pileCode("TEST001")
|
||||
.gunNo("1")
|
||||
.tradeNo("trade-001")
|
||||
.success(true)
|
||||
.build();
|
||||
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-007")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("REMOTE_START_RESULT")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(resultData)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试无效消息类型
|
||||
*/
|
||||
@Test
|
||||
public void testHandleInvalidMessageType() throws Exception {
|
||||
JcppUplinkMessage message = JcppUplinkMessage.builder()
|
||||
.messageId("msg-008")
|
||||
.sessionId("session-001")
|
||||
.protocolName("YKC_V1.6")
|
||||
.pileCode("TEST001")
|
||||
.messageType("INVALID_TYPE")
|
||||
.timestamp(System.currentTimeMillis())
|
||||
.data(new HashMap<>())
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/jcpp/uplink")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(message)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.success").value(false));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.jsowell.jcpp;
|
||||
|
||||
import com.jsowell.pile.jcpp.dto.JcppPricingModel;
|
||||
import com.jsowell.pile.jcpp.util.PricingModelConverter;
|
||||
import com.jsowell.pile.vo.web.BillingDetailVO;
|
||||
import com.jsowell.pile.vo.web.BillingTemplateVO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* 计费模板转换工具类测试
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
public class PricingModelConverterTest {
|
||||
|
||||
/**
|
||||
* 测试标准计费模板转换
|
||||
*/
|
||||
@Test
|
||||
public void testConvertStandardPricing() {
|
||||
BillingTemplateVO template = new BillingTemplateVO();
|
||||
template.setId(1L);
|
||||
template.setName("标准计费模板");
|
||||
|
||||
List<BillingDetailVO> details = new ArrayList<>();
|
||||
BillingDetailVO detail = new BillingDetailVO();
|
||||
detail.setTimeType("3"); // 平时
|
||||
detail.setElectricityPrice(new BigDecimal("0.8"));
|
||||
detail.setServicePrice(new BigDecimal("0.4"));
|
||||
detail.setApplyTime("00:00-24:00");
|
||||
details.add(detail);
|
||||
template.setBillingDetailList(details);
|
||||
|
||||
JcppPricingModel model = PricingModelConverter.convert(template);
|
||||
|
||||
assertNotNull(model);
|
||||
assertEquals(1L, model.getPricingId());
|
||||
assertEquals("标准计费模板", model.getPricingName());
|
||||
assertEquals(1, model.getPricingType()); // 标准计费
|
||||
assertEquals(new BigDecimal("0.8"), model.getElectricityPrice());
|
||||
assertEquals(new BigDecimal("0.4"), model.getServicePrice());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试峰谷计费模板转换
|
||||
*/
|
||||
@Test
|
||||
public void testConvertPeakValleyPricing() {
|
||||
BillingTemplateVO template = new BillingTemplateVO();
|
||||
template.setId(2L);
|
||||
template.setName("峰谷计费模板");
|
||||
|
||||
List<BillingDetailVO> details = new ArrayList<>();
|
||||
|
||||
// 尖时
|
||||
BillingDetailVO sharpDetail = new BillingDetailVO();
|
||||
sharpDetail.setTimeType("1");
|
||||
sharpDetail.setElectricityPrice(new BigDecimal("1.2"));
|
||||
sharpDetail.setServicePrice(new BigDecimal("0.6"));
|
||||
sharpDetail.setApplyTime("10:00-12:00,18:00-20:00");
|
||||
details.add(sharpDetail);
|
||||
|
||||
// 峰时
|
||||
BillingDetailVO peakDetail = new BillingDetailVO();
|
||||
peakDetail.setTimeType("2");
|
||||
peakDetail.setElectricityPrice(new BigDecimal("1.0"));
|
||||
peakDetail.setServicePrice(new BigDecimal("0.5"));
|
||||
peakDetail.setApplyTime("08:00-10:00,12:00-18:00");
|
||||
details.add(peakDetail);
|
||||
|
||||
// 平时
|
||||
BillingDetailVO flatDetail = new BillingDetailVO();
|
||||
flatDetail.setTimeType("3");
|
||||
flatDetail.setElectricityPrice(new BigDecimal("0.8"));
|
||||
flatDetail.setServicePrice(new BigDecimal("0.4"));
|
||||
flatDetail.setApplyTime("06:00-08:00,20:00-22:00");
|
||||
details.add(flatDetail);
|
||||
|
||||
// 谷时
|
||||
BillingDetailVO valleyDetail = new BillingDetailVO();
|
||||
valleyDetail.setTimeType("4");
|
||||
valleyDetail.setElectricityPrice(new BigDecimal("0.4"));
|
||||
valleyDetail.setServicePrice(new BigDecimal("0.2"));
|
||||
valleyDetail.setApplyTime("00:00-06:00,22:00-24:00");
|
||||
details.add(valleyDetail);
|
||||
|
||||
template.setBillingDetailList(details);
|
||||
|
||||
JcppPricingModel model = PricingModelConverter.convert(template);
|
||||
|
||||
assertNotNull(model);
|
||||
assertEquals(2L, model.getPricingId());
|
||||
assertEquals("峰谷计费模板", model.getPricingName());
|
||||
assertEquals(2, model.getPricingType()); // 峰谷计费
|
||||
|
||||
// 验证峰谷价格
|
||||
JcppPricingModel.PeakValleyPrice peakValley = model.getPeakValleyPrice();
|
||||
assertNotNull(peakValley);
|
||||
assertEquals(new BigDecimal("1.2"), peakValley.getSharpElectricityPrice());
|
||||
assertEquals(new BigDecimal("0.6"), peakValley.getSharpServicePrice());
|
||||
assertEquals(new BigDecimal("1.0"), peakValley.getPeakElectricityPrice());
|
||||
assertEquals(new BigDecimal("0.5"), peakValley.getPeakServicePrice());
|
||||
assertEquals(new BigDecimal("0.8"), peakValley.getFlatElectricityPrice());
|
||||
assertEquals(new BigDecimal("0.4"), peakValley.getFlatServicePrice());
|
||||
assertEquals(new BigDecimal("0.4"), peakValley.getValleyElectricityPrice());
|
||||
assertEquals(new BigDecimal("0.2"), peakValley.getValleyServicePrice());
|
||||
|
||||
// 验证时段配置
|
||||
assertNotNull(peakValley.getTimePeriodConfigs());
|
||||
assertFalse(peakValley.getTimePeriodConfigs().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试空模板转换
|
||||
*/
|
||||
@Test
|
||||
public void testConvertNullTemplate() {
|
||||
JcppPricingModel model = PricingModelConverter.convert((BillingTemplateVO) null);
|
||||
assertNull(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试无详情模板转换
|
||||
*/
|
||||
@Test
|
||||
public void testConvertTemplateWithoutDetails() {
|
||||
BillingTemplateVO template = new BillingTemplateVO();
|
||||
template.setId(3L);
|
||||
template.setName("无详情模板");
|
||||
template.setBillingDetailList(null);
|
||||
|
||||
JcppPricingModel model = PricingModelConverter.convert(template);
|
||||
|
||||
assertNotNull(model);
|
||||
assertEquals(3L, model.getPricingId());
|
||||
assertEquals(1, model.getPricingType()); // 默认标准计费
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user