diff --git a/jsowell-admin/src/test/java/SpringBootTestController.java b/jsowell-admin/src/test/java/SpringBootTestController.java index 834070554..9bdcba8eb 100644 --- a/jsowell-admin/src/test/java/SpringBootTestController.java +++ b/jsowell-admin/src/test/java/SpringBootTestController.java @@ -21,13 +21,17 @@ import com.jsowell.common.core.domain.ykc.TransactionRecordsData; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.ykc.OrderStatusEnum; import com.jsowell.common.enums.ykc.StartModeEnum; +import com.jsowell.common.enums.ykc.YKCChargingStopReasonEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.*; +import com.jsowell.common.util.Cp56Time2a.Cp56Time2aUtil; import com.jsowell.common.util.http.HttpUtils; +import com.jsowell.common.util.id.IdUtils; import com.jsowell.common.util.id.SnUtils; import com.jsowell.common.util.id.SnowflakeIdWorker; import com.jsowell.common.util.ip.AddressUtils; import com.jsowell.netty.handler.HeartbeatRequestHandler; +import com.jsowell.netty.handler.TransactionRecordsRequestHandler; import com.jsowell.netty.service.yunkuaichong.YKCBusinessService; import com.jsowell.pile.domain.*; import com.jsowell.pile.domain.ykcCommond.IssueQRCodeCommand; @@ -170,6 +174,268 @@ public class SpringBootTestController { @Autowired private AMapService aMapService; + @Autowired + private TransactionRecordsRequestHandler transactionRecordsRequestHandler; + + + @Test + public void testTransactionRecord() { + // 获取消息体 + String msg = "8823000000123302230707215317078588230000001233020000341507071763023615070717b02a0200a00f0000000000003016000090dc010000000000000000000000000020c50100000000000000000000000000888a0100000000000000000000000000b0220749005032074900a00f000000000000e01500004c4e425343433448314c543130373634360563023615070717450000000000000000"; + byte[] msgBody = BytesUtil.str2Bcd(msg); + + int startIndex = 0; + int length = 16; + + // 交易流水号 + byte[] orderCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String transactionCode = BytesUtil.bcd2Str(orderCodeByteArr); + + // 桩编码 + startIndex += length; + length = 7; + byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String pileSn = BytesUtil.bcd2Str(pileSnByteArr); + + // 枪号 + startIndex += length; + length = 1; + byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr); + + + // 开始时间 CP56Time2a 格式 + startIndex += length; + length = 7; + byte[] startTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + // String binary = BytesUtil.binary(startTimeByteArr, 16); + Date startDate = Cp56Time2aUtil.byte2Hdate(startTimeByteArr); + String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startDate); + + + // 结束时间 CP56Time2a 格式 + startIndex += length; + byte[] endTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + Date endDate = Cp56Time2aUtil.byte2Hdate(endTimeByteArr); + String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endDate); + + // 尖单价 精确到小数点后五位(尖电费+尖服务费,见费率帧) + startIndex += length; + length = 4; + byte[] sharpPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String sharpPrice = YKCUtils.convertDecimalPoint(sharpPriceByteArr, 5); + + // 尖电量 精确到小数点后四位 + startIndex += length; + length = 4; + byte[] sharpUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String sharpUsedElectricity = YKCUtils.convertDecimalPoint(sharpUsedElectricityByteArr, 4); + + // 计损尖电量 + startIndex += length; + byte[] sharpPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String sharpPlanLossElectricity = YKCUtils.convertDecimalPoint(sharpPlanLossElectricityByteArr, 4); + + // 尖金额 + startIndex += length; + byte[] sharpAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String sharpAmount = YKCUtils.convertDecimalPoint(sharpAmountByteArr, 4); + + // 峰单价 精确到小数点后五位(峰电费+峰服务费) + startIndex += length; + byte[] peakPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String peakPrice = YKCUtils.convertDecimalPoint(peakPriceByteArr, 5); + + // 峰电量 + startIndex += length; + byte[] peakUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String peakUsedElectricity = YKCUtils.convertDecimalPoint(peakUsedElectricityByteArr, 4); + + // 计损峰电量 + startIndex += length; + byte[] peakPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String peakPlanLossElectricity = YKCUtils.convertDecimalPoint(peakPlanLossElectricityByteArr, 4); + + // 峰金额 + startIndex += length; + byte[] peakAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String peakAmount = YKCUtils.convertDecimalPoint(peakAmountByteArr, 4); + + // 平单价 精确到小数点后五位(平电费+平服务费) + startIndex += length; + byte[] flatPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String flatPrice = YKCUtils.convertDecimalPoint(flatPriceByteArr, 5); + + // 平电量 + startIndex += length; + byte[] flatUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String flatUsedElectricity = YKCUtils.convertDecimalPoint(flatUsedElectricityByteArr, 4); + + // 计损平电量 + startIndex += length; + byte[] flatPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String flatPlanLossElectricity = YKCUtils.convertDecimalPoint(flatPlanLossElectricityByteArr, 4); + + // 平金额 + startIndex += length; + byte[] flatAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String flatAmount = YKCUtils.convertDecimalPoint(flatAmountByteArr, 4); + + // 谷单价 精确到小数点后五位(谷电费+谷 服务费) + startIndex += length; + byte[] valleyPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String valleyPrice = YKCUtils.convertDecimalPoint(valleyPriceByteArr, 5); + + // 谷电量 + startIndex += length; + byte[] valleyUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String valleyUsedElectricity = YKCUtils.convertDecimalPoint(valleyUsedElectricityByteArr, 4); + + // 计损谷电量 + startIndex += length; + byte[] valleyPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String valleyPlanLossElectricity = YKCUtils.convertDecimalPoint(valleyPlanLossElectricityByteArr, 4); + + // 谷金额 + startIndex += length; + byte[] valleyAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String valleyAmount = YKCUtils.convertDecimalPoint(valleyAmountByteArr, 4); + + // 电表总起值 + startIndex += length; + length = 5; + byte[] ammeterTotalStartByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String ammeterTotalStart = YKCUtils.convertDecimalPoint(ammeterTotalStartByteArr, 4); + + // 电表总止值 + startIndex += length; + byte[] ammeterTotalEndByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String ammeterTotalEnd = YKCUtils.convertDecimalPoint(ammeterTotalEndByteArr, 4); + + // 总电量 + startIndex += length; + length = 4; + byte[] totalElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String totalElectricity = YKCUtils.convertDecimalPoint(totalElectricityByteArr, 4); + + // 计损总电量 + startIndex += length; + byte[] planLossTotalElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String planLossTotalElectricity = YKCUtils.convertDecimalPoint(planLossTotalElectricityByteArr, 4); + + // 消费金额 精确到小数点后四位,包含电费、 服务费 + startIndex += length; + byte[] consumptionAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String consumptionAmount = YKCUtils.convertDecimalPoint(consumptionAmountByteArr, 4); + + // VIN 码 VIN 码,此处 VIN 码和充电时 VIN 码不同, 正序直接上传, 无需补 0 和反序 + startIndex += length; + length = 17; + byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String vinCode = BytesUtil.ascii2Str(vinCodeByteArr); + + /** + * 交易标识 + * 0x01: app 启动 + * 0x02:卡启动 + * 0x04:离线卡启动 + * 0x05: vin 码启动充电 + */ + startIndex += length; + length = 1; + byte[] transactionIdentifierByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String transactionIdentifier = BytesUtil.bcd2Str(transactionIdentifierByteArr); + + // 交易时间 CP56Time2a 格式 + startIndex += length; + length = 7; + byte[] transactionTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + Date transactionDate = Cp56Time2aUtil.byte2Hdate(transactionTimeByteArr); + String transactionTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, transactionDate); + + // 停止原因 + startIndex += length; + length = 1; + byte[] stopReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String stopReason = BytesUtil.bin2HexStr(stopReasonByteArr); + String stopReasonMsg = YKCChargingStopReasonEnum.getMsgByCode(Integer.parseInt(stopReason, 16)); + + // 物理卡号 不足 8 位补 0 + startIndex += length; + length = 8; + byte[] cardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + // byte[] logicCardNum = BytesUtil.checkLengthAndBehindAppendZero(cardNumByteArr, 16); + String logicCard = BytesUtil.binary(cardNumByteArr, 16); + // log.info("桩号:{}发送交易记录物理卡号:{}", pileSn, logicCard); + // + // log.info("[===交易记录===]交易流水号:{}, 桩编号:{}, 枪号:{}, 开始时间:{}, 结束时间:{}, 尖单价:{}, 尖电量:{}, 计损尖电量:{}, 尖金额:{}, " + + // "峰单价:{}, 峰电量:{}, 计损峰电量:{}, 峰金额:{}, 平单价:{}, 平电量:{}, 计损平电量:{}, 平金额:{}, " + + // "谷单价:{}, 谷电量:{}, 计损谷电量:{}, 谷金额:{}, 电表总起值:{}, 电表总止值:{}, 总电量:{}, 计损总电量:{}, 消费金额:{}, " + + // "电动汽车唯一标识:{}, 交易标识:{}, 交易日期、时间:{}, 停止原因码:{}, 停止原因描述:{}, 物理卡号:{}", + // transactionCode, pileSn, connectorCode, startTime, endTime, sharpPrice, sharpUsedElectricity, sharpPlanLossElectricity, sharpAmount, + // peakPrice, peakUsedElectricity, peakPlanLossElectricity, peakAmount, flatPrice, flatUsedElectricity, flatPlanLossElectricity, flatAmount, + // valleyPrice, valleyUsedElectricity, valleyPlanLossElectricity, valleyAmount, ammeterTotalStart, ammeterTotalEnd, totalElectricity, planLossTotalElectricity, + // consumptionAmount, vinCode, transactionIdentifier, transactionTime, stopReason, stopReasonMsg, logicCard); + + // 交易记录封装到对象里 + TransactionRecordsData data = TransactionRecordsData.builder() + // .orderCode(transactionCode) + .transactionCode(transactionCode) + .pileSn(pileSn) + .connectorCode(connectorCode) + .startTime(startTime) + .endTime(endTime) + .sharpPrice(sharpPrice) + .sharpUsedElectricity(sharpUsedElectricity) + .sharpPlanLossElectricity(sharpPlanLossElectricity) + .sharpAmount(sharpAmount) + .peakPrice(peakPrice) + .peakUsedElectricity(peakUsedElectricity) + .peakPlanLossElectricity(peakPlanLossElectricity) + .peakAmount(peakAmount) + .flatPrice(flatPrice) + .flatUsedElectricity(flatUsedElectricity) + .flatPlanLossElectricity(flatPlanLossElectricity) + .flatAmount(flatAmount) + .valleyPrice(valleyPrice) + .valleyUsedElectricity(valleyUsedElectricity) + .valleyPlanLossElectricity(valleyPlanLossElectricity) + .valleyAmount(valleyAmount) + .ammeterTotalStart(ammeterTotalStart) + .ammeterTotalEnd(ammeterTotalEnd) + .totalElectricity(totalElectricity) + .planLossTotalElectricity(planLossTotalElectricity) + .consumptionAmount(consumptionAmount) + .vinCode(vinCode) + .transactionIdentifier(transactionIdentifier) + .transactionTime(transactionTime) + .stopReasonMsg(stopReasonMsg) + .logicCard(logicCard) + .build(); + + // boolean flag = !StringUtils.equals("0000000000000000", "a511101970000000"); + // System.out.println(flag); + + // 处理订单加锁 + String lockKey = "settle_order_" + transactionCode; + String uuid = IdUtils.fastUUID(); + try { + // redis锁 + Boolean isLock = redisCache.lock(lockKey, uuid, 1500); + if (isLock) { + transactionRecordsRequestHandler.processOrder(data); + } + } catch (Exception e) { + System.out.println("处理订单发生异常: " + e); + } finally { + if (uuid.equals(redisCache.getCacheObject(lockKey).toString())) { + redisCache.unLock(lockKey); + } + } + } + + + @Test public void testQueryCorpMember() { try {