对接jcpp

This commit is contained in:
Guoqs
2025-12-27 15:05:41 +08:00
parent bc3e8091de
commit 7d170dbe64
35 changed files with 5185 additions and 0 deletions

View File

@@ -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));
}
}

View File

@@ -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()); // 默认标准计费
}
}