This commit is contained in:
2023-03-04 16:29:55 +08:00
commit 397ba75479
1007 changed files with 109050 additions and 0 deletions

View File

@@ -0,0 +1,264 @@
package com.jsowell.pile.service.impl;
import com.google.common.collect.Lists;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.MemberBasicInfo;
import com.jsowell.pile.domain.MemberWalletInfo;
import com.jsowell.pile.domain.MemberWalletLog;
import com.jsowell.pile.mapper.MemberBasicInfoMapper;
import com.jsowell.pile.mapper.MemberWalletInfoMapper;
import com.jsowell.pile.mapper.MemberWalletLogMapper;
import com.jsowell.pile.mapper.PileBasicInfoMapper;
import com.jsowell.pile.service.IMemberBasicInfoService;
import com.jsowell.pile.service.IPileBasicInfoService;
import com.jsowell.pile.vo.uniapp.MemberVO;
import com.jsowell.pile.vo.uniapp.MemberWalletLogVO;
import com.jsowell.pile.vo.uniapp.PersonalPileInfoVO;
import com.jsowell.pile.vo.web.UpdateMemberBalanceDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
/**
* 会员基础信息Service业务层处理
*
* @author jsowell
* @date 2022-10-12
*/
@Slf4j
@Service
public class MemberBasicInfoServiceImpl implements IMemberBasicInfoService {
@Autowired
private MemberBasicInfoMapper memberBasicInfoMapper;
@Autowired
private MemberWalletInfoMapper memberWalletInfoMapper;
@Autowired
private MemberWalletLogMapper memberWalletLogMapper;
@Autowired
private IPileBasicInfoService pileBasicInfoService;
/**
* 查询会员基础信息
*
* @param id 会员基础信息主键
* @return 会员基础信息
*/
@Override
public MemberBasicInfo selectMemberBasicInfoById(Integer id) {
return memberBasicInfoMapper.selectMemberBasicInfoById(id);
}
/**
* 查询会员基础信息列表
*
* @param memberBasicInfo 会员基础信息
* @return 会员基础信息
*/
/*@Override
public List<MemberVO> selectMemberBasicInfoList(MemberBasicInfo memberBasicInfo) {
List<MemberVO> voList = memberBasicInfoMapper.selectMemberList(memberBasicInfo.getMobileNumber(), memberBasicInfo.getNickName());
for (MemberVO memberVO : voList) {
memberVO.setPrincipalBalance(memberVO.getPrincipalBalance() == null ? BigDecimal.ZERO : memberVO.getPrincipalBalance());
memberVO.setGiftBalance(memberVO.getGiftBalance() == null ? BigDecimal.ZERO : memberVO.getGiftBalance());
}
return voList;
}*/
/**
* 新增会员基础信息
*
* @param memberBasicInfo 会员基础信息
* @return 结果
*/
@Override
public int insertMemberBasicInfo(MemberBasicInfo memberBasicInfo) {
memberBasicInfo.setCreateTime(DateUtils.getNowDate());
return memberBasicInfoMapper.insertMemberBasicInfo(memberBasicInfo);
}
/**
* 修改会员基础信息
*
* @param memberBasicInfo 会员基础信息
* @return 结果
*/
@Override
public int updateMemberBasicInfo(MemberBasicInfo memberBasicInfo) {
memberBasicInfo.setUpdateTime(DateUtils.getNowDate());
return memberBasicInfoMapper.updateMemberBasicInfo(memberBasicInfo);
}
/**
* 批量删除会员基础信息
*
* @param ids 需要删除的会员基础信息主键
* @return 结果
*/
@Override
public int deleteMemberBasicInfoByIds(List<Integer> ids) {
return memberBasicInfoMapper.deleteMemberBasicInfoByIds(ids);
}
/**
* 通过物理卡号查询会员基本信息
*
* @param physicsCard 物理卡号
* @return 会员基本信息
*/
@Override
public MemberVO selectInfoByPhysicsCard(String physicsCard) {
return memberBasicInfoMapper.selectInfoByPhysicsCard(physicsCard);
}
/**
* 根据手机号和运营商id查询会员信息
* @param mobileNumber 手机号
* @param merchantId 运营商id
* @return 会员信息
*/
public MemberBasicInfo selectInfoByMobileNumberAndMerchantId(String mobileNumber, String merchantId) {
return memberBasicInfoMapper.selectInfoByMobileNumberAndMerchantId(mobileNumber, merchantId);
}
@Override
public MemberBasicInfo selectInfoByMobileNumber(String mobileNumber) {
return selectInfoByMobileNumberAndMerchantId(mobileNumber, null);
}
@Override
public MemberBasicInfo selectInfoByMemberId(String memberId) {
return memberBasicInfoMapper.selectInfoByMemberId(memberId);
}
/**
* 修改用户余额 唯一方法
* 接收的金额都是正数,通过操作类型判断 充值还是扣减
*/
@Override
public int updateMemberBalance(UpdateMemberBalanceDTO dto) {
String memberId = dto.getMemberId();
BigDecimal updateGiftBalance = dto.getUpdateGiftBalance();
BigDecimal updatePrincipalBalance = dto.getUpdatePrincipalBalance();
log.info("修改用户余额 memberId:{}, updatePrincipalBalance:{}, updateGiftBalance:{}", memberId, updatePrincipalBalance, updateGiftBalance);
// 查询用户余额
MemberWalletInfo info = memberWalletInfoMapper.selectByMemberId(memberId);
if (info == null) {
log.warn("根据会员id:{}, 查询会员信息为空", memberId);
return 0;
}
// 记录流水
List<MemberWalletLog> logList = Lists.newArrayList();
// 计算新的余额
BigDecimal newPrincipalBalance = null;
BigDecimal newGiftBalance = null;
// 更新本金金额
if (updatePrincipalBalance != null) {
if (StringUtils.equals(dto.getType(), "2")) {
// 扣款 转为负数
updatePrincipalBalance = updatePrincipalBalance.negate();
}
// 会员老的余额
BigDecimal oldPrincipalBalance = info.getPrincipalBalance() == null
? BigDecimal.ZERO
: info.getPrincipalBalance();
newPrincipalBalance = oldPrincipalBalance.add(updatePrincipalBalance);
if (newPrincipalBalance.compareTo(BigDecimal.ZERO) < 0) {
log.warn("新本金余额不能为负数");
return 0;
}
// 记流水
logList.add(MemberWalletLog.builder()
.memberId(dto.getMemberId())
.type(dto.getType())
.subType(dto.getSubType())
.amount(updatePrincipalBalance)
.category("1")
.relatedOrderCode(dto.getRelatedOrderCode())
.createBy(dto.getMemberId())
.build());
}
// 更新赠送金额
if (updateGiftBalance != null) {
if (StringUtils.equals(dto.getType(), "2")) {
// 扣款 转为负数
updateGiftBalance = updateGiftBalance.negate();
}
BigDecimal oldGiftBalance = info.getGiftBalance() == null
? BigDecimal.ZERO
: info.getGiftBalance();
newGiftBalance = oldGiftBalance.add(updateGiftBalance);
// 余额不能为负数
if (newGiftBalance.compareTo(BigDecimal.ZERO) < 0) {
log.warn("新赠送余额不能为负数");
return 0;
}
// 记流水
logList.add(MemberWalletLog.builder()
.memberId(dto.getMemberId())
.type(dto.getType())
.subType(dto.getSubType())
.amount(updateGiftBalance)
.category("2")
.relatedOrderCode(dto.getRelatedOrderCode())
.createBy(dto.getMemberId())
.build());
}
// 修改数据库
int i = 0;
if (newPrincipalBalance != null || newGiftBalance != null) {
i = memberBasicInfoMapper.updateMemberBalance(memberId, newPrincipalBalance, newGiftBalance, info.getVersion());
if (i == 0) {
log.warn("修改余额失败, memberId:{}", memberId);
}
}
// 插入 member_wallet_log 表
if (CollectionUtils.isNotEmpty(logList)) {
memberWalletLogMapper.batchInsert(logList);
}
return i;
}
@Override
public MemberVO queryMemberInfoByMemberId(String memberId) {
// 加缓存
MemberVO vo = memberBasicInfoMapper.queryMemberInfoByMemberId(memberId);
return vo;
}
@Override
public List<MemberVO> selectMemberList(String mobileNumber, String nickName) {
return memberBasicInfoMapper.selectMemberList(mobileNumber, nickName);
}
/**
* 查询用户账户余额变动信息
* @param memberId 会员id
* @param type 1-进账2-出账 不传查全部
*/
@Override
public List<MemberWalletLogVO> getMemberBalanceChanges(String memberId, String type) {
return memberWalletLogMapper.getMemberBalanceChanges(memberId, type);
}
/**
* 通过memberId查询会员的个人桩信息
* @param memberId
* @return
*/
@Override
public List<PersonalPileInfoVO> getMemberPersonPileInfo(String memberId) {
return pileBasicInfoService.getPileInfoByMemberId(memberId);
}
}

View File

@@ -0,0 +1,41 @@
package com.jsowell.pile.service.impl;
import com.google.common.collect.Lists;
import com.jsowell.common.util.bean.BeanUtils;
import com.jsowell.pile.domain.MemberTransactionRecord;
import com.jsowell.pile.mapper.MemberTransactionRecordMapper;
import com.jsowell.pile.service.IMemberTransactionRecordService;
import com.jsowell.pile.vo.web.MemberTransactionVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class MemberTransactionRecordServiceImpl implements IMemberTransactionRecordService {
@Resource
private MemberTransactionRecordMapper memberTransactionRecordMapper;
@Override
public int insertSelective(MemberTransactionRecord record) {
return memberTransactionRecordMapper.insertSelective(record);
}
@Override
public List<MemberTransactionVO> selectMemberTransactionRecordList(String memberId) {
List<MemberTransactionRecord> list = memberTransactionRecordMapper.selectByMemberId(memberId);
if (CollectionUtils.isEmpty(list)) {
return Lists.newArrayList();
}
List<MemberTransactionVO> resultList = Lists.newArrayList();
for (MemberTransactionRecord memberTransactionRecord : list) {
MemberTransactionVO vo = new MemberTransactionVO();
BeanUtils.copyBeanProp(vo, memberTransactionRecord);
resultList.add(vo);
}
return resultList;
}
}

View File

@@ -0,0 +1,46 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.MemberWalletInfo;
import com.jsowell.pile.mapper.MemberWalletInfoMapper;
import com.jsowell.pile.service.IMemberWalletInfoService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class MemberWalletInfoServiceImpl implements IMemberWalletInfoService {
@Resource
private MemberWalletInfoMapper memberWalletInfoMapper;
@Override
public int deleteByPrimaryKey(Integer id) {
return memberWalletInfoMapper.deleteByPrimaryKey(id);
}
@Override
public int insert(MemberWalletInfo record) {
return memberWalletInfoMapper.insert(record);
}
@Override
public int insertSelective(MemberWalletInfo record) {
return memberWalletInfoMapper.insertSelective(record);
}
@Override
public MemberWalletInfo selectByPrimaryKey(Integer id) {
return memberWalletInfoMapper.selectByPrimaryKey(id);
}
@Override
public int updateByPrimaryKeySelective(MemberWalletInfo record) {
return memberWalletInfoMapper.updateByPrimaryKeySelective(record);
}
@Override
public int updateByPrimaryKey(MemberWalletInfo record) {
return memberWalletInfoMapper.updateByPrimaryKey(record);
}
}

View File

@@ -0,0 +1,46 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.MemberWalletLog;
import com.jsowell.pile.mapper.MemberWalletLogMapper;
import com.jsowell.pile.service.IMemberWalletLogService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class MemberWalletLogServiceImpl implements IMemberWalletLogService {
@Resource
private MemberWalletLogMapper memberWalletLogMapper;
// @Override
// public int deleteByPrimaryKey(Integer id) {
// return memberWalletLogMapper.deleteByPrimaryKey(id);
// }
//
// @Override
// public int insert(MemberWalletLog record) {
// return memberWalletLogMapper.insert(record);
// }
//
// @Override
// public int insertSelective(MemberWalletLog record) {
// return memberWalletLogMapper.insertSelective(record);
// }
//
// @Override
// public MemberWalletLog selectByPrimaryKey(Integer id) {
// return memberWalletLogMapper.selectByPrimaryKey(id);
// }
//
// @Override
// public int updateByPrimaryKeySelective(MemberWalletLog record) {
// return memberWalletLogMapper.updateByPrimaryKeySelective(record);
// }
//
// @Override
// public int updateByPrimaryKey(MemberWalletLog record) {
// return memberWalletLogMapper.updateByPrimaryKey(record);
// }
}

View File

@@ -0,0 +1,88 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.OrderAbnormalRecord;
import com.jsowell.pile.mapper.OrderAbnormalRecordMapper;
import com.jsowell.pile.service.IOrderAbnormalRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 订单异常记录Service业务层处理
*
* @author jsowell
* @date 2023-02-13
*/
@Service
public class OrderAbnormalRecordServiceImpl implements IOrderAbnormalRecordService {
@Autowired
private OrderAbnormalRecordMapper orderAbnormalRecordMapper;
/**
* 查询订单异常记录
*
* @param id 订单异常记录主键
* @return 订单异常记录
*/
@Override
public OrderAbnormalRecord selectOrderAbnormalRecordById(Integer id) {
return orderAbnormalRecordMapper.selectOrderAbnormalRecordById(id);
}
/**
* 查询订单异常记录列表
*
* @param orderAbnormalRecord 订单异常记录
* @return 订单异常记录
*/
@Override
public List<OrderAbnormalRecord> selectOrderAbnormalRecordList(OrderAbnormalRecord orderAbnormalRecord) {
return orderAbnormalRecordMapper.selectOrderAbnormalRecordList(orderAbnormalRecord);
}
/**
* 新增订单异常记录
*
* @param orderAbnormalRecord 订单异常记录
* @return 结果
*/
@Override
public int insertOrderAbnormalRecord(OrderAbnormalRecord orderAbnormalRecord) {
// orderAbnormalRecord.setCreateTime(DateUtils.getNowDate());
return orderAbnormalRecordMapper.insertOrderAbnormalRecord(orderAbnormalRecord);
}
/**
* 修改订单异常记录
*
* @param orderAbnormalRecord 订单异常记录
* @return 结果
*/
@Override
public int updateOrderAbnormalRecord(OrderAbnormalRecord orderAbnormalRecord) {
return orderAbnormalRecordMapper.updateOrderAbnormalRecord(orderAbnormalRecord);
}
/**
* 批量删除订单异常记录
*
* @param ids 需要删除的订单异常记录主键
* @return 结果
*/
@Override
public int deleteOrderAbnormalRecordByIds(Integer[] ids) {
return orderAbnormalRecordMapper.deleteOrderAbnormalRecordByIds(ids);
}
/**
* 删除订单异常记录信息
*
* @param id 订单异常记录主键
* @return 结果
*/
@Override
public int deleteOrderAbnormalRecordById(Integer id) {
return orderAbnormalRecordMapper.deleteOrderAbnormalRecordById(id);
}
}

View File

@@ -0,0 +1,852 @@
package com.jsowell.pile.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jsowell.common.annotation.DataScope;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.core.domain.ykc.TransactionRecordsData;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.MemberWalletEnum;
import com.jsowell.common.enums.ykc.OrderPayModeEnum;
import com.jsowell.common.enums.ykc.OrderPayStatusEnum;
import com.jsowell.common.enums.ykc.OrderStatusEnum;
import com.jsowell.common.enums.ykc.PileConnectorDataBaseStatusEnum;
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.bean.BeanUtils;
import com.jsowell.common.util.id.SnowflakeIdWorker;
import com.jsowell.pile.domain.OrderAbnormalRecord;
import com.jsowell.pile.domain.OrderBasicInfo;
import com.jsowell.pile.domain.OrderDetail;
import com.jsowell.pile.domain.OrderPayRecord;
import com.jsowell.pile.domain.WxpayCallbackRecord;
import com.jsowell.pile.dto.IndexQueryDTO;
import com.jsowell.pile.dto.QueryOrderDTO;
import com.jsowell.pile.dto.QueryPersonPileDTO;
import com.jsowell.pile.mapper.OrderBasicInfoMapper;
import com.jsowell.pile.service.IMemberBasicInfoService;
import com.jsowell.pile.service.IOrderAbnormalRecordService;
import com.jsowell.pile.service.IOrderBasicInfoService;
import com.jsowell.pile.service.IOrderPayRecordService;
import com.jsowell.pile.service.IPileConnectorInfoService;
import com.jsowell.pile.service.WechatPayService;
import com.jsowell.pile.service.WxpayCallbackRecordService;
import com.jsowell.pile.transaction.dto.OrderTransactionDTO;
import com.jsowell.pile.transaction.service.TransactionService;
import com.jsowell.pile.vo.uniapp.*;
import com.jsowell.pile.vo.web.IndexOrderInfoVO;
import com.jsowell.pile.vo.web.OrderListVO;
import com.jsowell.pile.vo.web.OrderTotalDataVO;
import com.jsowell.pile.vo.web.PileConnectorInfoVO;
import com.jsowell.pile.vo.web.UpdateMemberBalanceDTO;
import com.jsowell.wxpay.common.WeChatPayParameter;
import com.jsowell.wxpay.dto.WeChatRefundDTO;
import com.jsowell.wxpay.dto.WechatSendMsgDTO;
import com.jsowell.wxpay.response.WechatPayRefundRequest;
import com.jsowell.wxpay.response.WechatPayRefundResponse;
import com.jsowell.wxpay.service.WxAppletRemoteService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 订单Service业务层处理
*
* @author jsowell
* @date 2022-09-30
*/
@Service
public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private OrderBasicInfoMapper orderBasicInfoMapper;
@Autowired
private TransactionService transactionService;
@Autowired
private RedisCache redisCache;
@Autowired
private IOrderPayRecordService orderPayRecordService;
@Autowired
private IMemberBasicInfoService memberBasicInfoService;
@Autowired
private WxpayCallbackRecordService wxpayCallbackRecordService;
@Autowired
private WechatPayService wechatPayService;
@Autowired
private IOrderAbnormalRecordService orderAbnormalRecordService;
@Autowired
private WxAppletRemoteService wxAppletRemoteService;
@Autowired
private IPileConnectorInfoService pileConnectorInfoService;
/**
* 查询订单
*
* @param id 订单主键
* @return 订单
*/
@Override
public OrderBasicInfo selectOrderBasicInfoById(Long id) {
return orderBasicInfoMapper.selectOrderBasicInfoById(id);
}
/**
* 条件查询订单基本信息
* @param info
* @return
*/
@Override
public OrderBasicInfo getOrderBasicInfo(OrderBasicInfo info) {
return orderBasicInfoMapper.getOrderBasicInfo(info);
}
/**
* 查询订单列表
*
* @param dto 订单
* @return 订单
*/
@Override
@DataScope(deptAlias = "t3")
public List<OrderListVO> selectOrderBasicInfoList(QueryOrderDTO dto) {
List<OrderListVO> orderListVOS = orderBasicInfoMapper.selectOrderBasicInfoList(dto);
if (CollectionUtils.isNotEmpty(orderListVOS)) {
for (OrderListVO orderListVO : orderListVOS) {
// 如果是微信支付,通过订单号查询微信支付单号
if (StringUtils.equals(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue(), orderListVO.getPayMode())) {
WxpayCallbackRecord wxpayCallbackRecord = wxpayCallbackRecordService.selectByOrderCode(orderListVO.getOrderCode());
orderListVO.setOutTradeNo(wxpayCallbackRecord.getOutTradeNo());
}
orderListVO.setPileConnectorCode(orderListVO.getPileSn() + orderListVO.getConnectorCode());
// 订单状态描述
String orderStatus = orderListVO.getOrderStatus(); // 订单状态
String payStatus = orderListVO.getPayStatus(); // 支付状态
String orderStatusDescribe;
if (StringUtils.equals(orderStatus, OrderStatusEnum.NOT_START.getValue())) {
// 未启动还有两种情况 待支付 / 支付成功
if (StringUtils.equals(payStatus, OrderPayStatusEnum.paid.getValue())) {
// 支付成功,未启动
orderStatusDescribe = OrderPayStatusEnum.paid.getLabel() + ", " + OrderStatusEnum.getOrderStatus(orderStatus);
} else {
// 待支付
orderStatusDescribe = OrderPayStatusEnum.unpaid.getLabel();
}
} else {
orderStatusDescribe = OrderStatusEnum.getOrderStatus(orderStatus);
}
orderListVO.setOrderStatusDescribe(orderStatusDescribe);
}
}
return orderListVOS;
}
/**
* 查询时间段内订单总金额和总用电量
*
* @param dto
* @return
*/
@Override
@DataScope(deptAlias = "t3")
public OrderTotalDataVO getOrderTotalData(QueryOrderDTO dto) {
OrderTotalDataVO vo = new OrderTotalDataVO();
dto.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue());
List<OrderListVO> list = orderBasicInfoMapper.selectOrderBasicInfoList(dto);
BigDecimal sumOrderAmount = BigDecimal.ZERO;
BigDecimal sumUsedElectricity = BigDecimal.ZERO;
vo.setDateDescription(dto.getStartTime() + " - " + dto.getEndTime());
if (CollectionUtils.isNotEmpty(list)) {
for (OrderListVO orderListVO : list) {
BigDecimal orderAmount = StringUtils.isBlank(orderListVO.getOrderAmount())
? BigDecimal.ZERO
: new BigDecimal(orderListVO.getOrderAmount());
sumOrderAmount = sumOrderAmount.add(orderAmount);
BigDecimal chargingDegree = StringUtils.isBlank(orderListVO.getChargingDegree())
? BigDecimal.ZERO
: new BigDecimal(orderListVO.getChargingDegree());
sumUsedElectricity = sumUsedElectricity.add(chargingDegree);
}
}
vo.setSumOrderAmount(sumOrderAmount);
vo.setSumUsedElectricity(sumUsedElectricity);
return vo;
}
/**
* 通过订单号查询订单信息(小程序发送消息用)
* @param orderCode
* @return
*/
@Override
public SendMessageVO selectOrderInfoByOrderCode(String orderCode) {
return orderBasicInfoMapper.selectOrderInfoByOrderCode(orderCode);
}
/**
* 充电桩启动失败
* @param orderCode
* @param failedReasonMsg
*/
@Override
public void chargingPileFailedToStart(String orderCode, String failedReasonMsg) {
OrderBasicInfo orderInfo = getOrderInfoByOrderCode(orderCode);
if (orderInfo == null) {
return;
}
// 启动失败原因
orderInfo.setReason(failedReasonMsg);
// 订单退款(结算订单)
TransactionRecordsData data = TransactionRecordsData.builder()
.orderCode(orderInfo.getOrderCode())
.consumptionAmount(String.valueOf(orderInfo.getOrderAmount()))
.stopReasonMsg(failedReasonMsg)
.totalElectricity(Constants.ZERO)
.sharpUsedElectricity(Constants.ZERO)
.peakUsedElectricity(Constants.ZERO)
.flatUsedElectricity(Constants.ZERO)
.valleyUsedElectricity(Constants.ZERO)
.build();
settleOrder(data, orderInfo);
}
/**
* 充电桩启动成功
* @param orderCode
*/
@Override
public void chargingPileStartedSuccessfully(String orderCode) {
OrderBasicInfo orderInfo = getOrderInfoByOrderCode(orderCode);
if (orderInfo == null) {
return;
}
// 启动成功,订单状态改为充电中
orderInfo.setOrderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue());
if (orderInfo.getChargeStartTime() == null) {
orderInfo.setChargeStartTime(new Date());
}
updateOrderBasicInfo(orderInfo);
}
public static void main(String[] args) {
Date date = DateUtils.addMinute(new Date(), -10);
System.out.println(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, date));
long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis - date.getTime() > 1000 * 60 * 15) {
// 已经支付超过15分钟
System.out.println("已经支付超过15分钟");
} else {
System.out.println("已经支付, 不到15分钟");
}
}
@Override
public void closeStartFailedOrder(String startTime, String endTime) {
List<OrderBasicInfo> orderList = orderBasicInfoMapper.selectOrderListByTimeRangeAndStatus(startTime, endTime, OrderStatusEnum.NOT_START.getValue(), OrderPayStatusEnum.paid.getValue());
List<String> orderCodeList = orderList.stream().map(OrderBasicInfo::getOrderCode).collect(Collectors.toList());
logger.info("{}-{}期间,共{}条,支付成功未启动订单,订单号:{}", startTime, endTime, orderList.size(), orderCodeList);
if (CollectionUtils.isEmpty(orderList)) {
return;
}
long currentTimeMillis = System.currentTimeMillis();
// 判断支付成功时间距当前时间是否大于15分钟
for (OrderBasicInfo orderBasicInfo : orderList) {
String orderCode = orderBasicInfo.getOrderCode();
Date payTime = orderBasicInfo.getPayTime();
if (payTime == null) {
continue;
}
long time = payTime.getTime();
if (currentTimeMillis - time < 1000 * 60 * 15) {
continue;
}
// 已经支付超过15分钟 判断充电桩的状态
String pileConnectorCode = orderBasicInfo.getPileSn() + orderBasicInfo.getConnectorCode();
PileConnectorInfoVO connector = pileConnectorInfoService.getPileConnectorInfoByConnectorCode(pileConnectorCode);
// 充电桩不在线,则不做处理。请联系管理员操作
if (PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue().equals(String.valueOf(connector.getStatus()))) {
logger.info("订单号:{}已经支付超过15分钟充电桩:{}未启动,但是该桩为离线状态,请联系管理员处理", orderCode, pileConnectorCode);
continue;
}
// 获取订单的实时检测数据,有实时数据说明充电了,没有实时数据说明桩确实没有充电
List<RealTimeMonitorData> chargingRealTimeData = getChargingRealTimeData(orderCode);
if (CollectionUtils.isEmpty(chargingRealTimeData)) {
// 充电桩在线并且没有0x13实时数据则执行结算退款操作
chargingPileFailedToStart(orderCode, "充电桩启动失败,执行退款处理");
}
}
}
/**
* 查询充电中的订单,没有数据权限校验,后管不要用
*
* @param pileSn
* @return
*/
@Override
public List<OrderListVO> selectChargingOrder(String pileSn) {
QueryOrderDTO dto = QueryOrderDTO.builder()
.pileSn(pileSn)
.orderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue())
.build();
return orderBasicInfoMapper.selectOrderBasicInfoList(dto);
}
/**
* 修改订单
*
* @param orderBasicInfo 订单
* @return 结果
*/
@Transactional
@Override
public int updateOrderBasicInfo(OrderBasicInfo orderBasicInfo) {
// 清缓存
String redisKey = CacheConstants.GET_ORDER_INFO_BY_ORDER_CODE + orderBasicInfo.getOrderCode();
redisCache.deleteObject(redisKey);
return orderBasicInfoMapper.updateOrderBasicInfo(orderBasicInfo);
}
/**
* 批量删除订单
*
* @param ids 需要删除的订单主键
* @return 结果
*/
@Transactional
@Override
public int deleteOrderBasicInfoByIds(Long[] ids) {
orderBasicInfoMapper.deleteOrderDetailByOrderCodes(ids);
return orderBasicInfoMapper.deleteOrderBasicInfoByIds(ids);
}
/**
* 通过订单号查询订单信息
*
* @param orderCode 订单号
* @return
*/
@Override
public OrderBasicInfo getOrderInfoByOrderCode(String orderCode) {
String redisKey = CacheConstants.GET_ORDER_INFO_BY_ORDER_CODE + orderCode;
OrderBasicInfo orderBasicInfo = redisCache.getCacheObject(redisKey);
if (orderBasicInfo == null) {
// 查数据库
orderBasicInfo = orderBasicInfoMapper.getOrderInfoByOrderCode(orderCode);
// 放缓存
if (orderBasicInfo != null) {
redisCache.setCacheObject(redisKey, orderBasicInfo, 5, TimeUnit.MINUTES);
}
}
logger.info("通过订单号:{}, 查询订单信息:{}", orderCode, JSON.toJSONString(orderBasicInfo));
return orderBasicInfo;
}
/**
* 根据充电桩编号和枪口号查询正在充电中的订单
* @param pileSn 桩编号
* @param connectorCode 枪口号
* @return
*/
@Override
public OrderBasicInfo queryChargingByPileSnAndConnectorCode(String pileSn, String connectorCode) {
return orderBasicInfoMapper.queryOrderBasicInfo(pileSn, connectorCode, OrderStatusEnum.IN_THE_CHARGING.getValue());
}
/**
* 根据枪口编号查询正在充电中的订单
* @param pileConnectorCode
* @return
*/
@Override
public OrderBasicInfo queryChargingByPileConnectorCode(String pileConnectorCode) {
if (StringUtils.isBlank(pileConnectorCode)) {
return null;
}
String pileSn = pileConnectorCode.substring(0, pileConnectorCode.length() - 2);
String connectorCode = pileConnectorCode.substring(pileConnectorCode.length() - 2);
return queryChargingByPileSnAndConnectorCode(pileSn, connectorCode);
}
/**
* 结算订单逻辑
*
* @param data 交易记录数据
* @param orderBasicInfo 订单主表信息,由调用方传过来
*/
@Override
public void settleOrder(TransactionRecordsData data, OrderBasicInfo orderBasicInfo) {
logger.info("结算订单start data:{}, orderBasicInfo:{}", data.toString(), orderBasicInfo.toString());
String orderCode = data.getOrderCode();
// 判断订单状态
if (StringUtils.equals(orderBasicInfo.getOrderStatus(), OrderStatusEnum.ORDER_COMPLETE.getValue())) {
logger.info("结算订单:{}, 是订单完成状态", orderCode);
return;
}
// 消费金额就是订单总金额
BigDecimal orderAmount = new BigDecimal(data.getConsumptionAmount());
// 付款金额 - 实际消费金额,如果有剩余,需要走退款操作 当使用余额支付时payAmount = principalPay + giftPay
BigDecimal payAmount = orderBasicInfo.getPayAmount();
// 有时候充电桩到达金额停止充电会多出一点金额比如实际需要充50元的电充电桩传来的消费金额为50.01元,在后台记录的时候需要舍去
if (orderAmount.compareTo(payAmount) > 0) {
logger.info("结算订单:【{}】充电桩传来的消费金额:【{}】大于付款金额:【{}】, 消费金额设置为付款金额相等数据", orderBasicInfo.getOrderCode(), orderAmount, payAmount);
orderAmount = payAmount;
}
// 剩余需要退回的金额 residue
BigDecimal residue = payAmount.subtract(orderAmount);
if (residue.compareTo(BigDecimal.ZERO) > 0) {
// 查支付记录
List<OrderPayRecord> payRecordList = orderPayRecordService.getOrderPayRecordList(orderBasicInfo.getOrderCode());
// 更新订单支付记录
List<OrderPayRecord> updatePayRecordList = Lists.newArrayList();
// 根据支付方式不同,走不同渠道退款
String payMode = orderBasicInfo.getPayMode();
if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) { // 余额支付
Map<String, OrderPayRecord> payRecordMap = payRecordList.stream()
.collect(Collectors.toMap(OrderPayRecord::getPayMode, Function.identity(), (k1, k2) -> k1));
// 取出本金支付金额,赠送支付金额
BigDecimal principalPay = null;
BigDecimal giftPay = null;
OrderPayRecord principalPayRecord = payRecordMap.get("1");
if (principalPayRecord != null) {
principalPay = principalPayRecord.getPayAmount();
}
OrderPayRecord giftPayRecord = payRecordMap.get("2");
if (giftPayRecord != null) {
giftPay = giftPayRecord.getPayAmount();
}
Map<String, BigDecimal> returnAmountMap = calculateReturnAmount(principalPay, giftPay, orderAmount);
logger.info("结算订单:{}, 剩余金额退回余额, 订单消费金额:{}, 本金支付金额:{}, 赠送支付金额:{}, 退回金额map:{}",
orderCode, orderAmount, principalPay, giftPay, JSONObject.toJSONString(returnAmountMap));
// 更新会员钱包
BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal");
if (returnPrincipal != null && principalPayRecord != null) {
principalPayRecord.setRefundAmount(returnPrincipal);
updatePayRecordList.add(principalPayRecord);
}
BigDecimal returnGift = returnAmountMap.get("returnGift");
if (returnGift != null && giftPayRecord != null) {
giftPayRecord.setRefundAmount(returnGift);
updatePayRecordList.add(giftPayRecord);
}
UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder()
.memberId(orderBasicInfo.getMemberId())
.type(MemberWalletEnum.TYPE_IN.getValue()) // 进账
.subType(MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue()) // 订单结算退款
.updatePrincipalBalance(returnPrincipal)
.updateGiftBalance(returnGift)
.relatedOrderCode(orderCode)
.build();
memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO);
} else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) { // 微信支付
// 微信退款逻辑
WeChatRefundDTO weChatRefundDTO = new WeChatRefundDTO();
weChatRefundDTO.setOrderCode(orderCode);
weChatRefundDTO.setRefundType("1");
weChatRefundDTO.setRefundAmount(residue);
this.weChatRefund(weChatRefundDTO);
// 订单支付记录
OrderPayRecord orderPayRecord = payRecordList.get(0);
orderPayRecord.setRefundAmount(residue);
updatePayRecordList.add(orderPayRecord);
} else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_ALIPAY.getValue())) { // 支付宝支付
// 支付宝退款逻辑
} else {
// 白名单支付
logger.info("订单:{}使用白名单支付,不进行退款处理", orderBasicInfo.getOrderCode());
}
// 更新order_pay_record
if (CollectionUtils.isNotEmpty(updatePayRecordList)) {
for (OrderPayRecord orderPayRecord : updatePayRecordList) {
orderPayRecordService.updateByPrimaryKeySelective(orderPayRecord);
}
}
}
// 修改订单数据
// 查询订单详情
OrderDetail orderDetail = getOrderDetailByOrderCode(orderCode);
// 把交易记录中的用电量,金额等信息 更新到orderBasicInfo和orderDetail
orderBasicInfo.setOrderAmount(orderAmount); // 订单总金额
orderBasicInfo.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue());
orderBasicInfo.setReason(data.getStopReasonMsg()); // 充电停止原因
orderBasicInfo.setSettlementTime(DateUtils.getNowDate()); // 结算时间
orderBasicInfo.setRefundAmount(residue); // 结算退款金额
orderDetail.setTotalUsedElectricity(new BigDecimal(data.getTotalElectricity())); // 总用电量
orderDetail.setTotalOrderAmount(orderAmount); // 订单总金额
orderDetail.setSharpUsedElectricity(new BigDecimal(data.getSharpUsedElectricity())); // 尖时段用电量
orderDetail.setPeakUsedElectricity(new BigDecimal(data.getPeakUsedElectricity())); // 峰时段用电量
orderDetail.setFlatUsedElectricity(new BigDecimal(data.getFlatUsedElectricity())); // 平时段用电量
orderDetail.setValleyUsedElectricity(new BigDecimal(data.getValleyUsedElectricity())); // 谷时段用电量
OrderTransactionDTO dto = new OrderTransactionDTO();
dto.setOrderBasicInfo(orderBasicInfo);
dto.setOrderDetail(orderDetail);
transactionService.doUpdateOrder(dto);
logger.info("结算订单 end OrderTransactionDTO:{}", JSONObject.toJSONString(dto));
try {
// uniApp 发送停止充电订阅消息
WechatSendMsgDTO wechatSendMsgDTO = new WechatSendMsgDTO();
wechatSendMsgDTO.setOrderCode(orderCode);
Map<String, String> resultMap = wxAppletRemoteService.stopChargingSendMsg(wechatSendMsgDTO);
logger.info("小程序发送充电停止推送消息 result:{}", JSON.toJSONString(resultMap));
}catch (Exception e) {
logger.error("小程序发送充电停止推送消息 error", e);
}
}
/**
* 余额支付 计算需要退回的金额
*
* @param principalPay
* @param giftPay
* @param orderAmount
* @return
*/
private Map<String, BigDecimal> calculateReturnAmount(BigDecimal principalPay, BigDecimal giftPay, BigDecimal orderAmount) {
Map<String, BigDecimal> resultMap = Maps.newHashMap();
// 消费金额优先使用本金
BigDecimal returnPrincipal = null; // 退回本金金额
BigDecimal returnGift = null; // 退回赠送金额
// 余额支付 有3种情况
if (principalPay != null && giftPay == null) {
// 只有本金支付
BigDecimal subtract = principalPay.subtract(orderAmount);
if (subtract.compareTo(BigDecimal.ZERO) > 0) {
returnPrincipal = subtract;
}
}
if (principalPay == null && giftPay != null) {
// 只有赠送金额支付
BigDecimal subtract = giftPay.subtract(orderAmount);
if (subtract.compareTo(BigDecimal.ZERO) > 0) {
returnGift = subtract;
}
}
if (principalPay != null && giftPay != null) {
// 本金+赠送支付
BigDecimal subtract = principalPay.subtract(orderAmount);
if (subtract.compareTo(BigDecimal.ZERO) > 0) {
// 本金减掉订单金额后还有剩余,那就把剩余的退回,赠送原封不动退回
returnPrincipal = subtract;
returnGift = giftPay;
} else if (subtract.compareTo(BigDecimal.ZERO) == 0) {
// 本金刚好够,那赠送金额支付的原封不动退回
returnGift = giftPay;
} else {
returnGift = giftPay.subtract(subtract.negate());
}
}
resultMap.put("returnPrincipal", returnPrincipal);
resultMap.put("returnGift", returnGift);
return resultMap;
}
/**
* 结算订单退款和用户余额退款调这个方法
*
* @param dto
*/
@Override
public void weChatRefund(WeChatRefundDTO dto) {
// 退款有两种情况 1-订单结算退款 2-用户余额退款
String refundType = dto.getRefundType();
if (StringUtils.equals(refundType, "1")) {
WechatPayRefundResponse response = refundForOrder(dto);
logger.info("订单结算退款 result:{}", JSONObject.toJSONString(response));
} else if (StringUtils.equals(refundType, "2")) {
WechatPayRefundResponse response = refundForBalance(dto);
logger.info("用户余额退款 result:{}", JSONObject.toJSONString(response));
} else {
logger.warn("没有找到退款处理逻辑");
}
}
@Override
public void saveAbnormalOrder(TransactionRecordsData data) {
OrderAbnormalRecord record = new OrderAbnormalRecord();
BeanUtils.copyBeanProp(record, data);
orderAbnormalRecordService.insertOrderAbnormalRecord(record);
}
/**
* 根据订单编号获取充电实时数据 时间倒序
* 订单只有在充电中才会把实时数据保存到redis
* @param orderCode 订单编号
* @return
*/
@Override
public List<RealTimeMonitorData> getChargingRealTimeData(String orderCode) {
List<RealTimeMonitorData> resultList = Lists.newArrayList();
if (StringUtils.isBlank(orderCode)) {
return resultList;
}
String pileConnectorCode = orderCode.substring(0, 16);
String redisKey = CacheConstants.PILE_REAL_TIME_MONITOR_DATA + pileConnectorCode + "_" + orderCode;
// 拿到所有数据
Map<Object, Object> map = redisCache.hmget(redisKey);
if (map != null && !map.isEmpty()) {
List<String> keyList = map.keySet().stream()
.map(x -> (String) x)
.sorted(Comparator.reverseOrder()) // 对keyList排序 时间倒序
.collect(Collectors.toList());
for (String s : keyList) {
Object o = map.get(s);
RealTimeMonitorData data = JSONObject.parseObject((String) o, RealTimeMonitorData.class);
resultList.add(data);
}
}
return resultList;
}
/**
* 首页订单数据展示
*
* @param dto 首页信息查询dto
* @return
*/
@Override
public List<IndexOrderInfoVO> getIndexOrderInfo(IndexQueryDTO dto) {
return orderBasicInfoMapper.getIndexOrderInfo(dto);
}
/**
* 获取超过15分钟的待支付状态订单
*
* @return
*/
@Override
public List<OrderBasicInfo> getUnpaidOrderListOver15Min() {
Date now = DateUtils.addMinute(new Date(), -15);
String nowString = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, now);
return orderBasicInfoMapper.getUnpaidOrderListOver15Min(nowString);
}
/**
* 根据orderId批量修改订单状态
*
* @param orderIds
* @param orderStatus
*/
@Override
public void updateOrderStatusById(List<String> orderIds, String orderStatus) {
orderBasicInfoMapper.updateOrderStatusById(orderIds, orderStatus);
}
@Override
public int close15MinutesOfUnpaidOrders() {
List<OrderBasicInfo> orderList = getUnpaidOrderListOver15Min();
if (CollectionUtils.isNotEmpty(orderList)) {
List<String> orderIdList = orderList.stream()
.map(x -> String.valueOf(x.getId()))
.collect(Collectors.toList());
// 修改订单状态
updateOrderStatusById(orderIdList, OrderStatusEnum.ORDER_CLOSE_TIMEOUT.getValue());
}
return orderList.size();
}
/**
* 订单退款处理逻辑
*/
private WechatPayRefundResponse refundForOrder(WeChatRefundDTO dto) {
// 查到orderCode对应的支付订单
// OrderBasicInfo orderInfo = this.getOrderInfoByOrderCode(dto.getOrderCode());
// // 校验订单
// if (Objects.isNull(orderInfo)) {
// logger.warn("orderCode:{}, 订单退款处理逻辑, 查询订单为空!", dto.getOrderCode());
// throw new BusinessException(ReturnCodeEnum.CODE_QUERY_ORDER_NULL_ERROR);
// }
// // 判断退款金额,不能大于支付金额
// BigDecimal payAmount = orderInfo.getPayAmount();
// // BigDecimal orderAmount = orderInfo.getOrderAmount();
// // BigDecimal amountToBeRefunded = payAmount.subtract(orderAmount); // 可退金额
// BigDecimal amountToBeRefunded = dto.getRefundAmount(); // 可退金额
// logger.info("订单:{}, 支付金额:{}, 需退款金额:{}", dto.getOrderCode(), payAmount, amountToBeRefunded);
// if (dto.getRefundAmount().compareTo(amountToBeRefunded) > 0) {
// // 退款金额,大于可退金额 抛出异常
// logger.warn("退款金额:{},大于可退金额{}, 抛出异常", dto.getRefundAmount(), amountToBeRefunded);
// throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_AMOUNT_ERROR);
// }
// 查出来原来的支付信息
WxpayCallbackRecord record = wxpayCallbackRecordService.selectByOrderCode(dto.getOrderCode());
if (Objects.isNull(record)) {
logger.warn("orderCode:{}, 订单退款处理逻辑, 查询订单微信支付记录为空!", dto.getOrderCode());
throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_CALLBACK_RECORD_ERROR);
}
// 判断支付金额和退款金额
int refundAmountInt = dto.getRefundAmount().multiply(new BigDecimal("100")).intValue();
int payerTotalInt = Integer.parseInt(record.getPayerTotal());
if (refundAmountInt > payerTotalInt) {
logger.warn("订单号:{}, 退款金额:{}(分),大于可退金额{}(分), 抛出异常", dto.getOrderCode(), refundAmountInt, payerTotalInt);
throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_AMOUNT_ERROR);
}
// 调微信退款接口
WechatPayRefundRequest request = new WechatPayRefundRequest();
request.setTransaction_id(record.getTransactionId()); // 微信支付单号
request.setOut_trade_no(record.getOutTradeNo()); // 商户订单号
// 生成退款单号
request.setOut_refund_no(SnowflakeIdWorker.getSnowflakeId()); // 商户退款单号
request.setNotify_url(WeChatPayParameter.refundNotifyUrl); // 回调接口
WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
amount.setRefund(refundAmountInt); // 退款金额
amount.setTotal(payerTotalInt); // 原订单金额
request.setAmount(amount);
request.setReason("订单结算退款");
request.setFunds_account("AVAILABLE");
try {
return wechatPayService.ApplyForWechatPayRefundV3(request);
} catch (JsonProcessingException e) {
logger.error("调微信退款API发生异常", e);
}
return null;
}
/**
* 余额退款处理逻辑
*
* @param dto
*/
private WechatPayRefundResponse refundForBalance(WeChatRefundDTO dto) {
// 查会员余额
MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(dto.getMemberId());
if (memberVO == null) {
throw new BusinessException(ReturnCodeEnum.CODE_SELECT_MEMBER_NULL_ERROR);
}
// 校验退款金额
BigDecimal principalBalance = memberVO.getPrincipalBalance();
BigDecimal refundAmount = dto.getRefundAmount();
if (refundAmount.compareTo(principalBalance) > 0) {
throw new BusinessException(ReturnCodeEnum.CODE_REFUND_MEMBER_BALANCE_ERROR);
}
// 退款金额 元转分 123
int totalCents = refundAmount.multiply(new BigDecimal(100)).intValue();
// 查询最近一年余额充值订单
List<WxpayCallbackRecord> recordList = wxpayCallbackRecordService.queryBalanceRechargeRecordOfTheLatestYear(dto.getMemberId());
// 也许需要多笔支付订单才够退款
List<WechatPayRefundRequest> requestList = Lists.newArrayList();
WechatPayRefundRequest request;
for (WxpayCallbackRecord record : recordList) {
int payerTotal = Integer.parseInt(record.getPayerTotal()); // 该笔支付订单的支付金额,单位分
totalCents = totalCents - payerTotal; // 123 - 100
request = new WechatPayRefundRequest();
request.setTransaction_id(record.getTransactionId()); // 微信支付单号
request.setOut_trade_no(record.getOutTradeNo()); // 商户订单号
request.setOut_refund_no(SnowflakeIdWorker.getSnowflakeId()); // 商户退款单号
request.setNotify_url(WeChatPayParameter.refundNotifyUrl); // 回调接口
request.setReason("用户余额退款");
request.setFunds_account("AVAILABLE");
if (totalCents > 0) {
// 如果大于0说明这笔单退完也不够
WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
amount.setRefund(payerTotal); // 退款金额
amount.setTotal(payerTotal); // 原订单金额
request.setAmount(amount);
requestList.add(request);
} else {
// 如果小于0这笔单退一部分
// 生成退款单号
WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
// 部分退
int i = payerTotal + totalCents;
amount.setRefund(i); // 退款金额
amount.setTotal(payerTotal); // 原订单金额
request.setAmount(amount);
requestList.add(request);
break;
}
}
// 调微信退款api
if (CollectionUtils.isNotEmpty(requestList)) {
for (WechatPayRefundRequest refundRequest : requestList) {
try {
return wechatPayService.ApplyForWechatPayRefundV3(refundRequest);
// logger.info("调微信退款API退款====={}", JSONObject.toJSONString(refundRequest));
} catch (Exception e) {
logger.error("调微信退款API发生异常", e);
}
}
}
return null;
}
/**
* 通过订单号查询订单详情
*
* @param orderCode 订单号
* @return 订单详情
*/
@Override
public OrderDetail getOrderDetailByOrderCode(String orderCode) {
return orderBasicInfoMapper.getOrderDetailByOrderCode(orderCode);
}
/**
* 通过会员Id和订单状态查询订单信息
*
* @param memberId 会员id
* @param orderStatusList 订单状态集合
* @return
*/
@Override
public List<OrderVO> getListByMemberIdAndOrderStatus(String memberId, List<String> orderStatusList) {
return orderBasicInfoMapper.getListByMemberIdAndOrderStatus(memberId, orderStatusList);
}
/**
* 个人桩查询充电数据
* @param dto
* @return
*/
@Override
public List<PersonPileConnectorSumInfoVO> getAccumulativeInfo(QueryPersonPileDTO dto) {
return orderBasicInfoMapper.getAccumulativeInfo(dto);
}
}

View File

@@ -0,0 +1,58 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.OrderPayRecord;
import com.jsowell.pile.mapper.OrderPayRecordMapper;
import com.jsowell.pile.service.IOrderPayRecordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class OrderPayRecordServiceImpl implements IOrderPayRecordService {
@Resource
private OrderPayRecordMapper orderPayRecordMapper;
// @Override
// public int deleteByPrimaryKey(Integer id) {
// return orderPayRecordMapper.deleteByPrimaryKey(id);
// }
// @Override
// public int insert(OrderPayRecord record) {
// return orderPayRecordMapper.insert(record);
// }
//
// @Override
// public int insertSelective(OrderPayRecord record) {
// return orderPayRecordMapper.insertSelective(record);
// }
// @Override
// public OrderPayRecord selectByPrimaryKey(Integer id) {
// return orderPayRecordMapper.selectByPrimaryKey(id);
// }
@Override
public int updateByPrimaryKeySelective(OrderPayRecord record) {
return orderPayRecordMapper.updateByPrimaryKeySelective(record);
}
// @Override
// public int updateByPrimaryKey(OrderPayRecord record) {
// return orderPayRecordMapper.updateByPrimaryKey(record);
// }
@Override
public int batchInsert(List<OrderPayRecord> payRecordList) {
return orderPayRecordMapper.batchInsert(payRecordList);
}
@Override
public List<OrderPayRecord> getOrderPayRecordList(String orderCode) {
return orderPayRecordMapper.getOrderPayRecordList(orderCode);
}
}

View File

@@ -0,0 +1,566 @@
package com.jsowell.pile.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.jsowell.common.annotation.DataScope;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.ykc.PileConnectorDataBaseStatusEnum;
import com.jsowell.common.enums.ykc.PileConnectorStatusEnum;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.PageUtils;
import com.jsowell.common.util.SecurityUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.PileBasicInfo;
import com.jsowell.pile.domain.PileConnectorInfo;
import com.jsowell.pile.domain.PileSimInfo;
import com.jsowell.pile.dto.IndexQueryDTO;
import com.jsowell.pile.dto.QueryPileDTO;
import com.jsowell.pile.dto.ReplaceMerchantStationDTO;
import com.jsowell.pile.mapper.PileBasicInfoMapper;
import com.jsowell.pile.mapper.PileMemberRelationMapper;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.base.MerchantInfoVO;
import com.jsowell.pile.vo.base.PileInfoVO;
import com.jsowell.pile.vo.uniapp.PersonalPileInfoVO;
import com.jsowell.pile.vo.uniapp.PileConnectorDetailVO;
import com.jsowell.pile.vo.web.IndexGeneralSituationVO;
import com.jsowell.pile.vo.web.PileDetailVO;
import com.jsowell.pile.vo.web.PileModelInfoVO;
import com.jsowell.pile.vo.web.SimCardVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 设备管理Service业务层处理
*
* @author jsowell
* @date 2022-08-26
*/
@Slf4j
@Service
public class PileBasicInfoServiceImpl implements IPileBasicInfoService {
@Autowired
private PileBasicInfoMapper pileBasicInfoMapper;
@Autowired
private IPileConnectorInfoService pileConnectorInfoService;
@Autowired
private IPileModelInfoService pileModelInfoService;
@Autowired
private IPileMerchantInfoService pileMerchantInfoService;
@Autowired
private IPileSimInfoService pileSimInfoService;
@Autowired
private SimCardService simCardService;
@Autowired
private RedisCache redisCache;
@Value("${qrcodeurl.prefix}")
private String QRCODE_URL_PREFIX;
/**
* 查询设备管理
*
* @param id 设备管理主键
* @return 设备管理
*/
@Override
public PileBasicInfo selectPileBasicInfoById(Long id) {
return pileBasicInfoMapper.selectPileBasicInfoById(id);
}
@Override
public PileBasicInfo selectPileBasicInfoBySN(String pileSn) {
return pileBasicInfoMapper.selectPileBasicInfoBySn(pileSn);
}
/**
* 查询设备管理列表
*
* @param pileBasicInfo 设备管理
* @return 设备管理
*/
@Override
public List<PileBasicInfo> selectPileBasicInfoList(PileBasicInfo pileBasicInfo) {
return pileBasicInfoMapper.selectPileBasicInfoList(pileBasicInfo);
}
/**
* 新增设备管理
*
* @param pileBasicInfo 设备管理
* @return 结果
*/
@Override
public int insertPileBasicInfo(PileBasicInfo pileBasicInfo) {
pileBasicInfo.setCreateBy(SecurityUtils.getUsername());
pileBasicInfo.setCreateTime(DateUtils.getNowDate());
return pileBasicInfoMapper.insertPileBasicInfo(pileBasicInfo);
}
/**
* 修改设备管理
*
* @param pileBasicInfo 设备管理
* @return 结果
*/
@Override
public int updatePileBasicInfo(PileBasicInfo pileBasicInfo) {
// pileBasicInfo.setUpdateBy(SecurityUtils.getUsername());
pileBasicInfo.setUpdateTime(DateUtils.getNowDate());
return pileBasicInfoMapper.updatePileBasicInfo(pileBasicInfo);
}
/**
* 批量删除设备管理
*
* @param ids 需要删除的设备管理主键
* @return 结果
*/
@Override
public int deletePileBasicInfoByIds(Long[] ids) {
return pileBasicInfoMapper.deletePileBasicInfoByIds(ids);
}
/**
* 删除设备管理信息
*
* @param id 设备管理主键
* @return 结果
*/
@Override
public int deletePileBasicInfoById(Long id) {
return pileBasicInfoMapper.deletePileBasicInfoById(id);
}
/**
* 查询充电桩信息
*
* @param dto 前台参数
* @return 充电桩信息集合
*/
@Override
@DataScope(deptAlias = "t2")
public List<PileDetailVO> queryPileInfos(QueryPileDTO dto) {
log.info("queryPileInfos dto:{}", JSONObject.toJSONString(dto));
// 首先不分页查询所有符合条件的充电桩
List<PileDetailVO> pileInfoVOS = queryPileInfoList(dto);
// 获取桩sn列表
List<String> pileSnList = pileInfoVOS.stream().map(PileDetailVO::getPileSn).collect(Collectors.toList());
// log.info("获取桩sn列表:{}", JSONObject.toJSONString(pileSnList));
// 批量获取桩状态 key:桩编号; value:状态
Map<String, String> pileStatusMap = pileConnectorInfoService.getPileStatus(pileSnList);
// log.info("批量获取桩状态:{}", JSONObject.toJSONString(pileStatusMap));
// 根据状态过滤
List<String> snList = Lists.newArrayList();
if (StringUtils.isNotBlank(dto.getStatus())) {
for (Map.Entry<String, String> entry : pileStatusMap.entrySet()) {
String pileSn = entry.getKey();
String pileStatus = entry.getValue();
if (StringUtils.equals(dto.getStatus(), pileStatus)) {
snList.add(pileSn);
}
}
} else {
// 不根据状态过滤snList就等于pileSnList
snList = pileSnList;
// 根据状态排序
}
if (CollectionUtils.isEmpty(snList)) {
return Lists.newArrayList();
}
// 使用snList查询 分页
if (dto.getPageNum() != 0) {
PageUtils.startPage();
}
QueryPileDTO queryPileDTO = new QueryPileDTO();
queryPileDTO.setPileSns(snList);
pileInfoVOS = queryPileInfoList(queryPileDTO);
for (PileDetailVO pileInfoVO : pileInfoVOS) {
pileInfoVO.setStatus(pileStatusMap.get(pileInfoVO.getPileSn()));
}
return pileInfoVOS;
}
@Override
// @DataScope(deptAlias = "t1")
public List<PileDetailVO> queryPileInfoList(QueryPileDTO queryPileDTO) {
return pileBasicInfoMapper.queryPileInfos(queryPileDTO);
}
/**
* 通过pileId更改运营商、站点信息
*
* @param dto 前台参数
* @return 结果
*/
@Override
public int replaceMerchantStationByPileIds(ReplaceMerchantStationDTO dto) {
dto.setUpdateBy(SecurityUtils.getUsername());
dto.setUpdateTime(DateUtils.getNowDate());
int num = pileBasicInfoMapper.replaceMerchantStationByPileIds(dto);
// 修改枪口信息
if (dto.getConnectorNum() != null && dto.getConnectorNum() > 0) {
// 先删后插
pileConnectorInfoService.deletePileConnectorInfoByPileSnList(dto.getPileSnList());
List<PileConnectorInfo> connectorInfoList = Lists.newArrayList();
for (String pileSn : dto.getPileSnList()) {
for (int i = 1; i < dto.getConnectorNum() + 1; i++) {
// 组装pile_connector_info表数据
PileConnectorInfo connectorInfo = new PileConnectorInfo();
connectorInfo.setPileSn(pileSn); // sn号
String connectorCode = String.format("%1$02d", i);
connectorInfo.setPileConnectorCode(pileSn + connectorCode); // 枪口编号
connectorInfo.setStatus(Constants.ZERO); //状态,默认 0-离网
connectorInfo.setCreateBy(SecurityUtils.getUsername()); // 创建人
connectorInfo.setDelFlag(Constants.DEL_FLAG_NORMAL); // 删除标识
connectorInfoList.add(connectorInfo);
}
}
if (CollectionUtils.isNotEmpty(connectorInfoList)) {
pileConnectorInfoService.batchInsertConnectorInfo(connectorInfoList);
}
}
return num;
}
/**
* 通过桩id查询basic信息
*
* @param id 桩id
* @return 结果集合
*/
@Override
public PileDetailVO selectBasicInfoById(Long id) {
PileDetailVO pileInfoVO = pileBasicInfoMapper.selectBasicInfoById(id);
if (pileInfoVO == null) {
return null;
}
// 获取桩状态
Map<String, String> pileStatusMap = pileConnectorInfoService.getPileStatus(Lists.newArrayList(pileInfoVO.getPileSn()));
pileInfoVO.setStatus(pileStatusMap.get(pileInfoVO.getPileSn()));
// String url = "http://localhost:8080/uniapp/pile/pileDetail/";
String pileQrCodeUrl = getPileQrCodeUrl(pileInfoVO.getPileSn());
pileInfoVO.setQrCodeURL(pileQrCodeUrl);
// 额定功率 瓦改为千瓦(2023.2.8发现数据库中型号表已经存的单位是 kw因此注释掉)
// pileInfoVO.setRatedPower(pileInfoVO.getRatedPower() / 1000);
return pileInfoVO;
}
@Override
public PileInfoVO selectPileInfoBySn(String pileSn) {
PileBasicInfo basicInfo = pileBasicInfoMapper.selectPileBasicInfoBySn(pileSn);
if (basicInfo == null) {
return null;
}
PileInfoVO pileInfoVO = PileInfoVO.builder()
.pileId(String.valueOf(basicInfo.getId()))
.pileSn(basicInfo.getSn())
.stationId(String.valueOf(basicInfo.getStationId()))
.merchantId(String.valueOf(basicInfo.getMerchantId()))
.build();
// 查站点信息
MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(basicInfo.getMerchantId()));
if (merchantInfo != null) {
pileInfoVO.setMerchantName(merchantInfo.getMerchantName());
}
// 查询充电桩额定功率
PileModelInfoVO pileModelInfoVO = pileModelInfoService.getPileModelInfoByPileSn(pileSn);
if (pileModelInfoVO != null) {
pileInfoVO.setRatedPower(pileModelInfoVO.getRatedPower());
pileInfoVO.setRatedCurrent(pileModelInfoVO.getRatedCurrent());
pileInfoVO.setRatedVoltage(pileModelInfoVO.getRatedVoltage());
}
return pileInfoVO;
}
@Override
public List<PileDetailVO> selectPileListByStationIds(List<Long> stationIdList) {
// 加缓存
List<PileDetailVO> pileInfoVOS = pileBasicInfoMapper.selectPileListByStationIds(stationIdList);
if (CollectionUtils.isEmpty(pileInfoVOS)) {
return Lists.newArrayList();
}
List<String> pileSnList = pileInfoVOS.stream().map(PileDetailVO::getPileSn).collect(Collectors.toList());
Map<String, String> pileStatusMap = pileConnectorInfoService.getPileStatus(pileSnList);
for (PileDetailVO pileInfoVO : pileInfoVOS) {
pileInfoVO.setStatus(pileStatusMap.get(pileInfoVO.getPileSn()));
}
return pileInfoVOS;
}
/**
* 通过桩sn号查询站点id
*
* @param sn 桩sn号
* @return 站点id
*/
// @Override
// public String selectStationIdBySn(String sn) {
// return pileBasicInfoMapper.selectStationIdBySn(sn);
// }
/**
* uniApp通过桩号查询桩详情
*
* @param pileSn 桩号
* @return
*/
// @Override
// public PileDetailVO uniAppGetPileDetailByPileSn(String pileSn) {
// PileDetailVO pileDetailVO = pileBasicInfoMapper.uniAppGetPileDetailByPileSn(pileSn);
// // 查询计费模板
// BillingTemplateVO billingTemplateVO = pileBillingTemplateService.selectBillingTemplateDetailByPileSn(pileSn);
// if (Objects.nonNull(billingTemplateVO)) {
// pileDetailVO.setBillingTemplate(billingTemplateVO);
//
// }
// // 查询枪口相关信息
// List<ConnectorVO> connectorList = new ArrayList<>();
//
// return pileDetailVO;
// }
/**
* 修改状态
* 用于登陆协议,心跳包协议,上传实时数据协议 更新状态的方法
* 数据库状态
* 充电枪0-离线1-空闲2-占用未充电3-占用充电中4-占用预约锁定255-故障
* <p>
* 充电枪口状态在以下情况会改变
* 1.登陆成功后设置为【1-空闲】
* 2.心跳包传0x01故障设置为【255-故障】
* 3.上传实时数据枪状态传0x00离线设置为【0-离线】
* 4.上传实时数据枪状态传0x01故障设置为【255-故障】
* 5.上传实时数据枪状态传0x02空闲并且为插枪状态设置为【2-占用(未充电)】
* 6.上传实时数据枪状态传0x02空闲并且为未插枪状态设置为【1-空闲】
* 7.上传实时数据枪状态传0x03充电设置为【3-占用(充电中)】
*/
@Override
public void updateStatus(String frameType, String pileSn, String connectorCode, String status, String putGunType) {
// log.info("updateStatus传参帧类型:{}, 桩编号:{}, 枪口号:{}, 状态:{}, 插拔枪:{}", "0x" + frameType, pileSn, connectorCode, status, putGunType);
/*
0x01 登陆认证
登陆成功,把充电桩和枪口的状态都更新为【在线】
*/
if (StringUtils.equals(frameType, String.valueOf(YKCFrameTypeCode.LOGIN_CODE.getCode()))) {
// 枪口状态设置为【空闲】
pileConnectorInfoService.updateConnectorStatusByPileSn(pileSn, PileConnectorDataBaseStatusEnum.FREE.getValue());
}
/*
0x03 心跳包 枪口状态 0-正常 1-故障
心跳包会传过来枪口的状态,由枪口状态推导出来充电桩的状态。任意一个枪口状态为故障,则充电桩状态也是故障
*/
if (StringUtils.equals(frameType, BytesUtil.bcd2Str(YKCFrameTypeCode.HEART_BEAT_CODE.getBytes()))) {
// log.info("心跳包的修改状态逻辑 桩号:{}, 枪号:{}, 枪状态:{}", pileSn, connectorCode, status);
/*
更新充电桩接口的数据库状态
传入的状态为【1-故障】,就把枪口数据库改为故障
*/
if (StringUtils.equals(status, Constants.ONE)) {
// 故障
pileConnectorInfoService.updateConnectorStatus(pileSn + connectorCode, PileConnectorDataBaseStatusEnum.FAULT.getValue());
} else {
// 正常
// List<PileConnectorInfo> connectorInfoList = pileConnectorInfoService.selectPileConnectorInfoList(pileSn);
// for (PileConnectorInfo connectorInfo : connectorInfoList) {
// // 收到心跳包,只有在离线或故障时,修改为空闲状态
// if (StringUtils.equals(connectorInfo.getStatus(), PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue())
// || StringUtils.equals(connectorInfo.getStatus(), PileConnectorDataBaseStatusEnum.FAULT.getValue())) {
// pileConnectorInfoService.updateConnectorStatus(pileSn + connectorCode, PileConnectorDataBaseStatusEnum.FREE.getValue());
// }
// }
}
}
/*
0x13 上传实时数据 枪口状态 0x00离线 0x01故障 0x02空闲 0x03充电
根据传来的枪状态和是否插枪,判断状态
*/
if (StringUtils.equals(frameType, BytesUtil.bcd2Str(YKCFrameTypeCode.UPLOAD_REAL_TIME_MONITOR_DATA_CODE.getBytes()))
|| StringUtils.equals(frameType, BytesUtil.bcd2Str(YKCFrameTypeCode.UPLOAD_REAL_TIME_MONITOR_DATA_OLD_VERSION_CODE.getBytes()))) {
// log.info("上传实时数据中的修改状态逻辑 桩号:{}, 枪号:{}, 枪状态{}, 是否插枪:{}", pileSn, connectorCode, status, putGunType);
/**
* 更新枪状态
* connectorStatus 桩传过来的枪口状态: 0x00离线 0x01故障 0x02空闲 0x03充电
* 数据库状态0离网 (默认)1空闲2占用未充电3占用充电中4占用预约锁定 255故障
*/
String statusDataBase = ""; // 传给数据库的状态
if (StringUtils.equals(status, PileConnectorStatusEnum.OFF_NETWORK.getValue())) { // 离线
statusDataBase = PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue();
} else if (StringUtils.equals(status, PileConnectorStatusEnum.FAULT.getValue())) { // 故障
statusDataBase = PileConnectorDataBaseStatusEnum.FAULT.getValue();
} else if (StringUtils.equals(status, PileConnectorStatusEnum.FREE.getValue())) { // 空闲
//是否插枪 0x00否 0x01
if (StringUtils.equals(putGunType, Constants.ZERO_ONE)) {
// 空闲并插枪 设置为【占用(未充电)】
statusDataBase = PileConnectorDataBaseStatusEnum.OCCUPIED_NOT_CHARGED.getValue();
} else {
// 空闲没插枪 设置为【空闲】
statusDataBase = PileConnectorDataBaseStatusEnum.FREE.getValue();
}
} else if (StringUtils.equals(status, PileConnectorStatusEnum.OCCUPIED_CHARGING.getValue())) { // 充电
// 设置为【占用(充电中)】
statusDataBase = PileConnectorDataBaseStatusEnum.OCCUPIED_CHARGING.getValue();
}
pileConnectorInfoService.updateConnectorStatus(pileSn + connectorCode, statusDataBase);
}
}
/**
* 充电桩正在充电时的实时数据存到redis
* @param realTimeMonitorData 实时数据
*/
@Override
public void saveRealTimeMonitorData2Redis(RealTimeMonitorData realTimeMonitorData) {
// 保存到redis
String redisKey = CacheConstants.PILE_REAL_TIME_MONITOR_DATA + realTimeMonitorData.getPileConnectorCode() + "_" + realTimeMonitorData.getOrderCode();
// 设置接收到实时数据的时间
Date now = new Date();
realTimeMonitorData.setDateTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, now));
// 计算功率,后面查询要用
String power = new BigDecimal(realTimeMonitorData.getOutputVoltage())
.multiply(new BigDecimal(realTimeMonitorData.getOutputCurrent())).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
realTimeMonitorData.setOutputPower(power);
// 保存json字符串
String jsonMsg = JSONObject.toJSONString(realTimeMonitorData);
// 上传实时数据每10秒发送一次1分钟6次在同一分钟内只保留最后一条实时数据
redisCache.hset(redisKey, DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:00", now), jsonMsg);
}
@Override
public PileConnectorDetailVO queryPileConnectorDetail(String pileConnectorCode) {
return pileBasicInfoMapper.queryPileConnectorDetail(pileConnectorCode);
}
/**
* 返回充电桩二维码
* @param pileSn 如充电桩编号为空,则返回前缀 https://api.jsowellcloud.com/app-xcx-h5/pile/pileDetail/
* @return
*/
@Override
public String getPileQrCodeUrl(String pileSn) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(QRCODE_URL_PREFIX);
stringBuilder.append("/app-xcx-h5/pile/pileDetail/");
if (StringUtils.isNotEmpty(pileSn)) {
if (!stringBuilder.toString().endsWith("/")) {
stringBuilder.append("/");
}
stringBuilder.append(pileSn);
}
return stringBuilder.toString();
}
@Override
public void updatePileSimInfo(String pileSn, String iccid) {
PileBasicInfo basicInfo = selectPileBasicInfoBySN(pileSn);
if (basicInfo == null) {
return;
}
// 通过iccid查pile_sim_info
PileSimInfo simInfo = pileSimInfoService.getBasicInfoByIccId(iccid);
if (simInfo == null) {
SimCardVO simCardVO = simCardService.searchByLoop(iccid);
// pile_sim_info 新增数据
if (simCardVO != null) {
simInfo = PileSimInfo.builder()
.iccid(iccid)
.name(simCardVO.getName())
.simSupplier(simCardVO.getSimCardFactory())
.expireTime(DateUtils.parseDate(simCardVO.getExpiredTime()))
.operator(simCardVO.getSimCardOperator())
.status(simCardVO.getSimCardStatus())
.surplusData(String.valueOf(simCardVO.getResidualFlowRate()))
.totalData(String.valueOf(simCardVO.getPackageCapacity()))
.build();
}else {
// 卡商未查到信息,记录为新卡,只存卡号
simInfo = PileSimInfo.builder()
.iccid(iccid)
.build();
}
pileSimInfoService.insertPileSimInfo(simInfo);
// 拿到id
Long simId = simInfo.getId();
log.info("新保存的sim卡id:{}", simId);
// sim_id 更新到pile_basic_info
basicInfo.setSimId(simId);
} else {
// sim信息已经存库了 然后更新充电桩的sim卡
basicInfo.setSimId(simInfo.getId());
}
updatePileBasicInfo(basicInfo);
}
/**
* 后管首页基本信息查询
*
* @param dto 站点Id
* @return 首页基本信息
*/
@Override
public IndexGeneralSituationVO getGeneralSituation(IndexQueryDTO dto) {
//
return pileBasicInfoMapper.getGeneralSituation(dto);
}
/**
* 通过会员id查询个人桩列表
* @param memberId
* @return
*/
@Override
public List<PersonalPileInfoVO> getPileInfoByMemberId(String memberId) {
List<PersonalPileInfoVO> list = pileBasicInfoMapper.getPileInfoByMemberId(memberId);
if(CollectionUtils.isEmpty(list)){
return null;
}
for (PersonalPileInfoVO personalPileInfoVO : list) {
String pileSn = personalPileInfoVO.getPileSn();
// 获取桩状态
Map<String, String> pileStatus = pileConnectorInfoService.getPileStatus(Lists.newArrayList(pileSn));
personalPileInfoVO.setPileStatus(pileStatus.get(pileSn));
if (StringUtils.equals("1", personalPileInfoVO.getType())) {
personalPileInfoVO.setType("管理员用户");
}else {
personalPileInfoVO.setType("普通用户");
}
if (StringUtils.equals("1", personalPileInfoVO.getSpeedType())) {
personalPileInfoVO.setSpeedType("快充");
}else {
personalPileInfoVO.setSpeedType("慢充");
}
}
return list;
}
}

View File

@@ -0,0 +1,619 @@
package com.jsowell.pile.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Bytes;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.enums.DelFlagEnum;
import com.jsowell.common.enums.ykc.BillingTimeEnum;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.SecurityUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.common.util.id.Seq;
import com.jsowell.pile.domain.PileBillingDetail;
import com.jsowell.pile.domain.PileBillingRelation;
import com.jsowell.pile.domain.PileBillingTemplate;
import com.jsowell.pile.dto.BillingTimeDTO;
import com.jsowell.pile.dto.CreateOrUpdateBillingTemplateDTO;
import com.jsowell.pile.dto.ImportBillingTemplateDTO;
import com.jsowell.pile.mapper.PileBillingTemplateMapper;
import com.jsowell.pile.service.IPileBasicInfoService;
import com.jsowell.pile.service.IPileBillingTemplateService;
import com.jsowell.pile.transaction.dto.BillingTemplateTransactionDTO;
import com.jsowell.pile.transaction.service.TransactionService;
import com.jsowell.pile.vo.uniapp.BillingPriceVO;
import com.jsowell.pile.vo.uniapp.CurrentTimePriceDetails;
import com.jsowell.pile.vo.web.BillingDetailVO;
import com.jsowell.pile.vo.web.BillingTemplateVO;
import com.jsowell.pile.vo.web.EchoBillingTemplateVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 计费模板Service业务层处理
*
* @author jsowell
* @date 2022-09-20
*/
@Slf4j
@Service
public class PileBillingTemplateServiceImpl implements IPileBillingTemplateService {
@Autowired
private PileBillingTemplateMapper pileBillingTemplateMapper;
@Autowired
private TransactionService transactionService;
@Autowired
private IPileBasicInfoService pileBasicInfoService;
/**
* 查询计费模板
*
* @param id 计费模板主键
* @return 计费模板
*/
@Override
public PileBillingTemplate selectPileBillingTemplateById(Long id) {
return pileBillingTemplateMapper.selectPileBillingTemplateById(id);
}
/**
* 查询计费模板列表
*
* @param pileBillingTemplate 计费模板
* @return 计费模板
*/
@Override
public List<PileBillingTemplate> selectPileBillingTemplateList(PileBillingTemplate pileBillingTemplate) {
return pileBillingTemplateMapper.selectPileBillingTemplateList(pileBillingTemplate);
}
/**
* 新增计费模板
*
* @param pileBillingTemplate 计费模板
* @return 结果
*/
@Transactional
@Override
public int insertPileBillingTemplate(PileBillingTemplate pileBillingTemplate) {
pileBillingTemplate.setCreateTime(DateUtils.getNowDate());
int rows = pileBillingTemplateMapper.insertPileBillingTemplate(pileBillingTemplate);
insertPileBillingDetail(pileBillingTemplate);
return rows;
}
/**
* 修改计费模板
*
* @param pileBillingTemplate 计费模板
* @return 结果
*/
@Transactional
@Override
public int updatePileBillingTemplate(PileBillingTemplate pileBillingTemplate) {
return pileBillingTemplateMapper.updatePileBillingTemplate(pileBillingTemplate);
}
/**
* 批量删除计费模板
*
* @param ids 需要删除的计费模板主键
* @return 结果
*/
@Transactional
@Override
public int deletePileBillingTemplateByIds(Long[] ids) {
// 查询计费模板详情列表
List<PileBillingDetail> pileBillingDetails = pileBillingTemplateMapper.queryBillingDetailByTemplateIds(ids);
if (CollectionUtils.isNotEmpty(pileBillingDetails)) {
List<String> templateCodes = pileBillingDetails.stream().map(PileBillingDetail::getTemplateCode).collect(Collectors.toList());
pileBillingTemplateMapper.deletePileBillingDetailByTemplateCodes(templateCodes);
}
return pileBillingTemplateMapper.deletePileBillingTemplateByIds(ids);
}
/**
* 删除计费模板信息
*
* @param id 计费模板主键
* @return 结果
*/
@Transactional
@Override
public int deletePileBillingTemplateById(Long id) {
// pileBillingTemplateMapper.deletePileBillingDetailByTemplateCode(id);
return pileBillingTemplateMapper.deletePileBillingTemplateById(id);
}
@Override
public void createBillingTemplate(CreateOrUpdateBillingTemplateDTO dto) {
// 生成计费模板编号
String templateCode = Seq.getId();
// 组装入库参数
PileBillingTemplate billingTemplate = new PileBillingTemplate();
billingTemplate.setName(dto.getName());
billingTemplate.setType(String.valueOf(dto.getType()));
billingTemplate.setRemark(dto.getRemark());
billingTemplate.setTemplateCode(templateCode);
billingTemplate.setCreateBy(SecurityUtils.getUsername());
billingTemplate.setDelFlag(DelFlagEnum.normal.getValue());
if (StringUtils.isBlank(dto.getStationId())) {
// 公共模板标识0-私有1-公共)
billingTemplate.setPublicFlag(Constants.ONE);
} else {
billingTemplate.setPublicFlag(Constants.ZERO);
}
// key为时间类型value为时间描述
Map<String, List<BillingTimeDTO>> map = dto.getTimeArray().stream()
.collect(Collectors.groupingBy(BillingTimeDTO::getType));
// 计费模板详情
List<PileBillingDetail> detailList = Lists.newArrayList();
PileBillingDetail detail = null;
for (BillingTimeEnum billingTimeEnum : BillingTimeEnum.values()) {
detail = new PileBillingDetail();
detail.setTemplateCode(templateCode);
String type = billingTimeEnum.getValue(); // 时段类型
detail.setTimeType(type);
Map<String, BigDecimal> priceMap = getPriceMap(dto, type);
detail.setElectricityPrice(priceMap.get("electricityPrice"));
detail.setServicePrice(priceMap.get("servicePrice"));
List<BillingTimeDTO> entryValue = map.get(type);
String applyTime = "";
if (CollectionUtils.isNotEmpty(entryValue)) {
applyTime = entryValue.stream()
.map(x -> x.getStartTime() + "-" + x.getEndTime())
.collect(Collectors.joining(","));
}
detail.setApplyTime(applyTime);
detail.setCreateBy(SecurityUtils.getUsername());
detailList.add(detail);
}
BillingTemplateTransactionDTO build = BillingTemplateTransactionDTO.builder()
.billingTemplate(billingTemplate)
.detailList(detailList)
.build();
// 入库
transactionService.doCreateBillingTemplate(build);
}
@Override
public void updateBillingTemplate(CreateOrUpdateBillingTemplateDTO dto) {
PileBillingTemplate billingTemplate = selectPileBillingTemplateById(Long.valueOf(dto.getBillingTemplateId()));
if (billingTemplate == null) {
log.info("根据计费模板id{}查询为null。无法修改直接返回", dto.getBillingTemplateId());
return;
}
billingTemplate.setName(dto.getName());
billingTemplate.setType(String.valueOf(dto.getType()));
billingTemplate.setRemark(dto.getRemark());
billingTemplate.setUpdateBy(SecurityUtils.getUsername());
// key为时间类型value为时间描述
Map<String, List<BillingTimeDTO>> map = dto.getTimeArray().stream()
.collect(Collectors.groupingBy(BillingTimeDTO::getType));
// 计费模板详情
List<PileBillingDetail> detailList = Lists.newArrayList();
PileBillingDetail detail = null;
for (BillingTimeEnum billingTimeEnum : BillingTimeEnum.values()) {
detail = new PileBillingDetail();
detail.setTemplateCode(billingTemplate.getTemplateCode());
String type = billingTimeEnum.getValue(); // 时段类型
detail.setTimeType(type);
Map<String, BigDecimal> priceMap = getPriceMap(dto, type);
detail.setElectricityPrice(priceMap.get("electricityPrice"));
detail.setServicePrice(priceMap.get("servicePrice"));
List<BillingTimeDTO> entryValue = map.get(type);
String applyTime = "";
if (CollectionUtils.isNotEmpty(entryValue)) {
applyTime = entryValue.stream()
.map(x -> x.getStartTime() + "-" + x.getEndTime())
.collect(Collectors.joining(","));
}
detail.setApplyTime(applyTime);
detail.setCreateBy(SecurityUtils.getUsername());
detailList.add(detail);
}
BillingTemplateTransactionDTO build = BillingTemplateTransactionDTO.builder()
.billingTemplate(billingTemplate)
.detailList(detailList)
.build();
// 入库
transactionService.doUpdateBillingTemplate(build);
}
@Override
public EchoBillingTemplateVO queryPileBillingTemplateById(Long id) {
PileBillingTemplate pileBillingTemplate = selectPileBillingTemplateById(id);
if (pileBillingTemplate == null) {
return null;
}
EchoBillingTemplateVO result = new EchoBillingTemplateVO();
result.setBillingTemplateId(String.valueOf(id));
result.setName(pileBillingTemplate.getName());
result.setRemark(pileBillingTemplate.getRemark());
result.setType(pileBillingTemplate.getType());
// 查计费模板详情
List<PileBillingDetail> detailList = pileBillingTemplateMapper.queryBillingDetailByTemplateIds(new Long[]{id});
if (CollectionUtils.isNotEmpty(detailList)) {
List<BillingTimeDTO> timeArray = Lists.newArrayList();
// 取出4个时间段类型
for (PileBillingDetail billingDetail : detailList) {
String type = billingDetail.getTimeType();
BigDecimal electricityPrice = billingDetail.getElectricityPrice();
BigDecimal servicePrice = billingDetail.getServicePrice();
if (StringUtils.equals(type, BillingTimeEnum.SHARP.getValue())) {
result.setElectricityPriceA(electricityPrice);
result.setServicePriceA(servicePrice);
} else if (StringUtils.equals(type, BillingTimeEnum.PEAK.getValue())) {
result.setElectricityPriceB(electricityPrice);
result.setServicePriceB(servicePrice);
} else if (StringUtils.equals(type, BillingTimeEnum.FLAT.getValue())) {
result.setElectricityPriceC(electricityPrice);
result.setServicePriceC(servicePrice);
} else if (StringUtils.equals(type, BillingTimeEnum.VALLEY.getValue())) {
result.setElectricityPriceD(electricityPrice);
result.setServicePriceD(servicePrice);
}
// 逗号拼接的时间段 00:00-01:30,01:30-04:00,23:30-24:00
String applyTime = billingDetail.getApplyTime();
if (StringUtils.isBlank(applyTime)) {
continue;
}
List<String> list = Lists.newArrayList(applyTime.split(","));
BillingTimeDTO timeDTO;
for (String s : list) {
String[] split = s.split("-");
timeDTO = new BillingTimeDTO();
timeDTO.setType(type);
timeDTO.setStartTime(split[0]);
timeDTO.setEndTime(split[1]);
timeArray.add(timeDTO);
}
}
// timeArray重新排序
result.setTimeArray(timeArray.stream().sorted(Comparator.comparing(BillingTimeDTO::getStartTime)).collect(Collectors.toList()));
}
return result;
}
/**
* 通过站点id查询当前时间的收费详情
*
* @param stationId 站点id
*/
@Override
public CurrentTimePriceDetails getCurrentTimePriceDetails(String stationId) {
CurrentTimePriceDetails result = null;
// 查询当前时段电费
LocalTime localTime = LocalTime.now();
String now = LocalTime.of(localTime.getHour(), localTime.getMinute(), localTime.getSecond()).toString();
// 通过站点id查询计费模板
BillingTemplateVO billingTemplateVO = pileBillingTemplateMapper.selectBillingTemplateByStationId(stationId);
if (Objects.nonNull(billingTemplateVO)) {
result = new CurrentTimePriceDetails();
result.setTemplateCode(billingTemplateVO.getTemplateCode());
result.setStationId(stationId);
result.setDateTime(localTime.toString());
List<BillingDetailVO> billingDetailList = billingTemplateVO.getBillingDetailList();
for (BillingDetailVO detailVO : billingDetailList) {
List<String> applyTimeList = detailVO.getApplyTime();
for (String applyTime : applyTimeList) {
boolean b = DateUtils.checkTime(now + "-" + now, applyTime);
if (b) {
// 将桩的费率存入stationVO
BigDecimal electricityPrice = detailVO.getElectricityPrice();
BigDecimal servicePrice = detailVO.getServicePrice();
result.setElectricityPrice(electricityPrice.toString());
result.setServicePrice(servicePrice.toString());
result.setTotalPrice(electricityPrice.add(servicePrice).toString());
}
}
}
}
return result;
}
@Override
public List<BillingTemplateVO> queryPublicBillingTemplateList() {
return pileBillingTemplateMapper.queryPublicBillingTemplateList();
}
@Override
public List<BillingTemplateVO> queryStationBillingTemplateList(String stationId) {
if (StringUtils.isBlank(stationId)) {
return Lists.newArrayList();
}
return pileBillingTemplateMapper.queryStationBillingTemplateList(stationId);
}
/**
* 查询正在使用中的计费模板
* 1 发布时间不为null
* 2 最近发布的为正在使用中的
* @param stationId 站点id
* @return
*/
@Override
public BillingTemplateVO queryUsedBillingTemplate(String stationId) {
List<BillingTemplateVO> list = queryStationBillingTemplateList(stationId);
Optional<BillingTemplateVO> max = list.stream()
.filter(x -> StringUtils.isNotBlank(x.getPublishTime()))
.max(Comparator.comparing(BillingTemplateVO::getPublishTime));
return max.orElse(null);
}
@Override
public List<BillingPriceVO> queryBillingPrice(String stationId) {
BillingTemplateVO billingTemplateVO = queryUsedBillingTemplate(stationId);
if (billingTemplateVO == null) {
return Lists.newArrayList();
}
EchoBillingTemplateVO echoBillingTemplateVO = queryPileBillingTemplateById(Long.parseLong(billingTemplateVO.getTemplateId()));
List<BillingTimeDTO> timeArray = echoBillingTemplateVO.getTimeArray();
log.info("计费模板时段:{}", JSONObject.toJSONString(timeArray));
List<BillingPriceVO> resultList = Lists.newArrayList();
for (BillingTimeDTO billingTimeDTO : timeArray) {
BillingPriceVO vo = new BillingPriceVO();
String type = billingTimeDTO.getType();
if (StringUtils.equals(type, BillingTimeEnum.SHARP.getValue())) {
vo.setElectricityPrice(billingTemplateVO.getSharpElectricityPrice().toString());
vo.setServicePrice(billingTemplateVO.getSharpServicePrice().toString());
} else if (StringUtils.equals(type, BillingTimeEnum.PEAK.getValue())) {
vo.setElectricityPrice(billingTemplateVO.getPeakElectricityPrice().toString());
vo.setServicePrice(billingTemplateVO.getPeakServicePrice().toString());
} else if (StringUtils.equals(type, BillingTimeEnum.FLAT.getValue())) {
vo.setElectricityPrice(billingTemplateVO.getFlatElectricityPrice().toString());
vo.setServicePrice(billingTemplateVO.getFlatServicePrice().toString());
} else if (StringUtils.equals(type, BillingTimeEnum.VALLEY.getValue())) {
vo.setElectricityPrice(billingTemplateVO.getValleyElectricityPrice().toString());
vo.setServicePrice(billingTemplateVO.getValleyServicePrice().toString());
}
// 总费用
vo.setTotalPrice(new BigDecimal(vo.getElectricityPrice()).add(new BigDecimal(vo.getServicePrice())).toString());
// 开始时间
vo.setStartTime(billingTimeDTO.getStartTime());
// 结束时间
String endTime = StringUtils.equals("24:00", billingTimeDTO.getEndTime()) ? "23:59" : billingTimeDTO.getEndTime();
vo.setEndTime(endTime);
// 时段类型
vo.setTimeType(type);
// 是否当前时间
boolean in = DateUtils.isIn(LocalTime.now(), LocalTime.parse(vo.getStartTime()), LocalTime.parse(vo.getEndTime()));
vo.setIsCurrentTime(in ? Constants.ONE : Constants.ZERO);
resultList.add(vo);
}
return resultList;
}
public static void main(String[] args) {
// 21:30-23:00
String startTime = "01:30";
String endTime = "23:00";
boolean in = DateUtils.isIn(LocalTime.now(), LocalTime.parse(startTime), LocalTime.parse(endTime));
System.out.println(in);
}
/**
* 通过桩sn号查询计费模板
*
* @param pileSn 桩sn
* @return 计费模板编号
*/
@Override
public BillingTemplateVO selectBillingTemplateDetailByPileSn(String pileSn) {
return pileBillingTemplateMapper.selectBillingTemplateByPileSn(pileSn);
}
@Override
public boolean stationImportBillingTemplate(ImportBillingTemplateDTO dto) {
// 查询公共计费模板是否存在
PileBillingTemplate pileBillingTemplate = pileBillingTemplateMapper.selectPileBillingTemplateById(Long.valueOf(dto.getBillingTemplateId()));
if (pileBillingTemplate == null) {
log.warn("根据计费模板id{},查询为空", dto.getBillingTemplateId());
return false;
}
List<PileBillingDetail> billingDetailList = pileBillingTemplate.getPileBillingDetailList();
// 复制计费模板
PileBillingTemplate stationBillingTemplate = new PileBillingTemplate();
String templateCode = Seq.getId(); // 生成计费模板编号
BeanUtils.copyProperties(pileBillingTemplate, stationBillingTemplate, "id", "createBy", "createTime", "updateBy", "updateTime");
stationBillingTemplate.setStationId(Long.valueOf(dto.getStationId())); // 站点id
stationBillingTemplate.setPublicFlag(Constants.ZERO); // 站点私有计费模板
stationBillingTemplate.setTemplateCode(templateCode);
stationBillingTemplate.setCreateBy(SecurityUtils.getUsername());
stationBillingTemplate.setDelFlag(DelFlagEnum.normal.getValue());
// 复制计费模板详情
List<PileBillingDetail> stationBillingDetailList = Lists.newArrayList();
PileBillingDetail pileBillingDetail;
for (PileBillingDetail detail : billingDetailList) {
pileBillingDetail = new PileBillingDetail();
BeanUtils.copyProperties(detail, pileBillingDetail, "id", "templateCode", "createBy", "createTime", "updateBy", "updateTime");
pileBillingDetail.setTemplateCode(templateCode);
pileBillingDetail.setCreateBy(SecurityUtils.getUsername());
pileBillingDetail.setDelFlag(DelFlagEnum.normal.getValue());
stationBillingDetailList.add(pileBillingDetail);
}
// 入库
BillingTemplateTransactionDTO billingTemplateTransactionDTO = new BillingTemplateTransactionDTO();
billingTemplateTransactionDTO.setBillingTemplate(stationBillingTemplate);
billingTemplateTransactionDTO.setDetailList(stationBillingDetailList);
transactionService.doCreateBillingTemplate(billingTemplateTransactionDTO);
return true;
}
@Override
public byte[] generateBillingTemplateMsgBody(String pileSn, BillingTemplateVO billingTemplateVO) {
if (StringUtils.isBlank(pileSn) || billingTemplateVO == null) {
log.error("生成发给充电桩的计费模板msgBody 参数不能为空");
return null;
}
// 桩编码
byte[] pileSnByte = BytesUtil.str2Bcd(pileSn);
// 计费模型编号 固定值: 01 00
byte[] billingTemplateCode = new byte[]{0x01, 0x00};
// 尖时段电费
byte[] sharpElectricityPrice = YKCUtils.getPriceByte(billingTemplateVO.getSharpElectricityPrice().toString(), 5);
// 尖时段服务费
byte[] sharpServicePrice = YKCUtils.getPriceByte(billingTemplateVO.getSharpServicePrice().toString(), 5);
// 峰时段电费
byte[] peakElectricityPrice = YKCUtils.getPriceByte(billingTemplateVO.getPeakElectricityPrice().toString(), 5);
// 峰时段服务费
byte[] peakServicePrice = YKCUtils.getPriceByte(billingTemplateVO.getPeakServicePrice().toString(), 5);
// 平时段电费
byte[] flatElectricityPrice = YKCUtils.getPriceByte(billingTemplateVO.getFlatElectricityPrice().toString(), 5);
// 平时段服务费
byte[] flatServicePrice = YKCUtils.getPriceByte(billingTemplateVO.getFlatServicePrice().toString(), 5);
// 谷时段电费
byte[] valleyElectricityPrice = YKCUtils.getPriceByte(billingTemplateVO.getValleyElectricityPrice().toString(), 5);
// 谷时段服务费
byte[] valleyServicePrice = YKCUtils.getPriceByte(billingTemplateVO.getValleyServicePrice().toString(), 5);
// 计损比例目前置0
byte[] PlanLossRatio = Constants.zeroByteArray;
// 48个时段费率半小时为一个时段
Map<Integer, List<String>> timeMap = billingTemplateVO.getTimeMap();
List<String> periodOfTime = DateUtils.getPeriodOfTime();
byte[] timeArray = new byte[periodOfTime.size()];
for (int i = 0; i < periodOfTime.size(); i++) {
// 对比时间段
byte timeType = getTimeType(periodOfTime.get(i), timeMap);
// log.info("时间段:{}, 对应费率类型:{}", periodOfTime.get(i), timeType);
timeArray[i] = timeType;
}
// 消息体
byte[] msgBody = Bytes.concat(pileSnByte, billingTemplateCode, sharpElectricityPrice, sharpServicePrice,
peakElectricityPrice, peakServicePrice, flatElectricityPrice, flatServicePrice, valleyElectricityPrice,
valleyServicePrice, PlanLossRatio, timeArray);
log.warn("generateBillingTemplateMsgBody:{}", BytesUtil.binary(msgBody, 16));
return msgBody;
}
/**
* 获取时段费率号
*
* @param timeRange 时间段 例如07:30:00-10:30:00
* @param timeMap 尖峰平谷4个类型的时间段每个类型都包含一个时间段集合
* @return
*/
private byte getTimeType(String timeRange, Map<Integer, List<String>> timeMap) {
byte b = 5;
// 这里的timeRange是00:00-00:30 这样的格式
String[] split = timeRange.split("-");
LocalTime startTime1 = DateUtils.getLocalTime(split[0]);
LocalTime endTime1 = DateUtils.getLocalTime(split[1]);
for (Map.Entry<Integer, List<String>> entry : timeMap.entrySet()) {
List<String> value = entry.getValue().stream().filter(StringUtils::isNotBlank).collect(Collectors.toList()); // 每个类型时间段集合
if (CollectionUtils.isEmpty(value)) {
continue;
}
for (String s : value) {
// 这里的s是07:30-10:30 这样的格式
List<String> list = Lists.newArrayList(s.split("-"));
LocalTime startTime2 = DateUtils.getLocalTime(list.get(0));
LocalTime endTime2 = DateUtils.getLocalTime(list.get(1));
boolean overlap = DateUtils.isOverlap(startTime1, endTime1, startTime2, endTime2, false);
if (overlap) {
return (byte) entry.getKey().intValue();
}
}
}
return b;
}
@Override
public BillingTemplateVO selectBillingTemplateByTemplateId(String templateId) {
return pileBillingTemplateMapper.selectBillingTemplateByTemplateId(templateId);
}
@Override
public void insertPileBillingRelation(List<PileBillingRelation> relationList) {
if (CollectionUtils.isEmpty(relationList)) {
return;
}
// 根据桩号删除计费模板关系
List<String> pileSnList = relationList.stream().map(PileBillingRelation::getPileSn).collect(Collectors.toList());
pileBillingTemplateMapper.deleteRelationByPileSn(pileSnList);
pileBillingTemplateMapper.insertPileBillingRelation(relationList);
}
private Map<String, BigDecimal> getPriceMap(CreateOrUpdateBillingTemplateDTO dto, String type) {
BigDecimal electricityPrice = null;
BigDecimal servicePrice = null;
if (StringUtils.equals(type, "1")) {
electricityPrice = dto.getElectricityPriceA();
servicePrice = dto.getServicePriceA();
} else if (StringUtils.equals(type, "2")) {
electricityPrice = dto.getElectricityPriceB();
servicePrice = dto.getServicePriceB();
} else if (StringUtils.equals(type, "3")) {
electricityPrice = dto.getElectricityPriceC();
servicePrice = dto.getServicePriceC();
} else if (StringUtils.equals(type, "4")) {
electricityPrice = dto.getElectricityPriceD();
servicePrice = dto.getServicePriceD();
}
Map<String, BigDecimal> resultMap = Maps.newHashMap();
resultMap.put("electricityPrice", electricityPrice);
resultMap.put("servicePrice", servicePrice);
return resultMap;
}
/**
* 新增计费模板详情信息
*
* @param pileBillingTemplate 计费模板对象
*/
public void insertPileBillingDetail(PileBillingTemplate pileBillingTemplate) {
List<PileBillingDetail> pileBillingDetailList = pileBillingTemplate.getPileBillingDetailList();
String templateCode = pileBillingTemplate.getTemplateCode();
if (StringUtils.isNotNull(pileBillingDetailList)) {
List<PileBillingDetail> list = new ArrayList<PileBillingDetail>();
for (PileBillingDetail pileBillingDetail : pileBillingDetailList) {
pileBillingDetail.setTemplateCode(templateCode);
list.add(pileBillingDetail);
}
if (list.size() > 0) {
pileBillingTemplateMapper.batchPileBillingDetail(list);
}
}
}
}

View File

@@ -0,0 +1,562 @@
package com.jsowell.pile.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.core.page.PageResponse;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.ykc.PileConnectorDataBaseStatusEnum;
import com.jsowell.common.enums.ykc.PileStatusEnum;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.OrderBasicInfo;
import com.jsowell.pile.domain.PileBasicInfo;
import com.jsowell.pile.domain.PileConnectorInfo;
import com.jsowell.pile.dto.QueryConnectorDTO;
import com.jsowell.pile.dto.QueryConnectorListDTO;
import com.jsowell.pile.mapper.PileBasicInfoMapper;
import com.jsowell.pile.mapper.PileConnectorInfoMapper;
import com.jsowell.pile.service.IOrderBasicInfoService;
import com.jsowell.pile.service.IPileBasicInfoService;
import com.jsowell.pile.service.IPileConnectorInfoService;
import com.jsowell.pile.service.IPileModelInfoService;
import com.jsowell.pile.vo.base.ConnectorInfoVO;
import com.jsowell.pile.vo.web.PileConnectorInfoVO;
import com.jsowell.pile.vo.web.PileDetailVO;
import com.jsowell.pile.vo.web.PileModelInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 充电桩枪口信息Service业务层处理
*
* @author jsowell
* @date 2022-08-31
*/
@Slf4j
@Service
public class PileConnectorInfoServiceImpl implements IPileConnectorInfoService {
@Autowired
private PileConnectorInfoMapper pileConnectorInfoMapper;
@Autowired
private PileBasicInfoMapper pileBasicInfoMapper;
@Autowired
private IPileBasicInfoService pileBasicInfoService;
@Autowired
private IPileModelInfoService pileModelInfoService;
@Autowired
private IOrderBasicInfoService orderBasicInfoService;
@Autowired
private RedisCache redisCache;
private final String URL = "http://localhost/pileConnectorInfo&code=";
@Value("${qrcodeurl.prefix}")
private String QRCODE_URL_PREFIX;
/**
* 查询充电桩枪口信息
*
* @param id 充电桩枪口信息主键
* @return 充电桩枪口信息
*/
@Override
public PileConnectorInfo selectPileConnectorInfoById(Integer id) {
return pileConnectorInfoMapper.selectPileConnectorInfoById(id);
}
/**
* 查询充电桩枪口信息列表
*
* @param pileConnectorInfo 充电桩枪口信息
* @return 充电桩枪口信息
*/
@Override
public List<PileConnectorInfo> selectPileConnectorInfoList(PileConnectorInfo pileConnectorInfo) {
return pileConnectorInfoMapper.selectPileConnectorInfoList(pileConnectorInfo);
}
/**
* 通过充电桩号查询枪口信息列表 加缓存
*
* @param pileSn 桩编号
* @return 枪口信息列表
*/
@Override
public List<PileConnectorInfo> selectPileConnectorInfoList(String pileSn) {
// 取缓存
String redisKey = CacheConstants.SELECT_PILE_CONNECTOR_INFO_LIST + pileSn;
List<PileConnectorInfo> result = redisCache.getCacheObject(redisKey);
if (CollectionUtils.isEmpty(result)) {
// 缓存为空,查数据库
PileConnectorInfo pileConnectorInfo = new PileConnectorInfo();
pileConnectorInfo.setPileSn(pileSn);
result = selectPileConnectorInfoList(pileConnectorInfo);
if (CollectionUtils.isNotEmpty(result)) {
// 查询数据库不为空存redis 2分钟
redisCache.setCacheObject(redisKey, result, 2, TimeUnit.MINUTES);
}
}
return result;
}
/**
* 公共方法 根据桩编号删除redis缓存
*/
private void deleteRedisByPileSn(String pileSn) {
List<String> keys = Lists.newArrayList();
// 删除枪口信息缓存
keys.add(CacheConstants.SELECT_PILE_CONNECTOR_INFO_LIST + pileSn);
// 删除充电桩详情缓存
keys.add(CacheConstants.PILE_DETAIL_KEY + pileSn);
// 删除充电桩枪口状态缓存
Set<String> scan = redisCache.scan(CacheConstants.PILE_CONNECTOR_STATUS_KEY + pileSn + "*");
if (CollectionUtils.isNotEmpty(scan)) {
keys.addAll(scan);
}
// 批量删除
// log.debug("批量删除缓存 pileSn:{}, keys:{}", pileSn, keys);
redisCache.deleteObject(keys);
}
/**
* 新增充电桩枪口信息
*
* @param pileConnectorInfo 充电桩枪口信息
* @return 结果
*/
// @Override
// public int insertPileConnectorInfo(PileConnectorInfo pileConnectorInfo) {
// pileConnectorInfo.setCreateTime(DateUtils.getNowDate());
// return pileConnectorInfoMapper.insertPileConnectorInfo(pileConnectorInfo);
// }
/**
* 修改充电桩枪口信息
*
* @param pileConnectorInfo 充电桩枪口信息
* @return 结果
*/
// @Override
// public int updatePileConnectorInfo(PileConnectorInfo pileConnectorInfo) {
// pileConnectorInfo.setUpdateTime(DateUtils.getNowDate());
// deleteRedisByPileSn(pileConnectorInfo.getPileSn());
// return pileConnectorInfoMapper.updatePileConnectorInfo(pileConnectorInfo);
// }
/**
* 批量删除充电桩枪口信息
*
* @param ids 需要删除的充电桩枪口信息主键
* @return 结果
*/
// @Override
// public int deletePileConnectorInfoByIds(Integer[] ids) {
// return pileConnectorInfoMapper.deletePileConnectorInfoByIds(ids);
// }
@Override
public int deletePileConnectorInfoByPileSnList(List<String> pileSnList) {
return pileConnectorInfoMapper.deletePileConnectorInfoByPileSnList(pileSnList);
}
@Override
public int batchInsertConnectorInfo(List<PileConnectorInfo> pileConnectorInfoList) {
return pileConnectorInfoMapper.batchInsertConnectorInfo(pileConnectorInfoList);
}
/**
* 充电接口相关信息
*
* @param dto 前台参数
* @return 充电接口对象结果集
*/
@Override
public List<PileConnectorInfoVO> getConnectorInfoListByParams(QueryConnectorDTO dto) {
List<PileConnectorInfoVO> list = pileConnectorInfoMapper.getConnectorInfoList(dto);
// 二维码、电量、设备订单号、平台订单暂时未传
if (Objects.nonNull(list)) {
for (PileConnectorInfoVO p : list) {
// p.setConnectorQrCodeUrl(URL + p.getPileConnectorCode());
p.setConnectorQrCodeUrl(getPileConnectorQrCodeUrl(p.getPileConnectorCode()));
}
}
return list;
}
/**
* 通过充电站id查询充电枪信息
*
* @param stationId 充电站id
* @return 充电接口信息集合
*/
@Override
public List<PileConnectorInfoVO> selectConnectorListByStationId(Long stationId) {
return pileConnectorInfoMapper.selectConnectorListByStationId(stationId);
}
/**
* 通过入参查询枪口数据
*
* @param dto
* @return
*/
@Override
public List<PileConnectorInfoVO> getConnectorInfoListByParams(QueryConnectorListDTO dto) {
int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum();
int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize();
List<String> pileSns = Lists.newArrayList();
List<Long> connectorIds = dto.getConnectorIdList();
List<Long> stationIdList = dto.getStationIdList();
List<String> connectorCodeList = dto.getConnectorCodeList();
// 通过运营商查询站点
if (StringUtils.isNotBlank(dto.getMerchantId())) {
// 查询站点idList
List<Long> queryStationIdList = Lists.newArrayList();
if (CollectionUtils.isNotEmpty(queryStationIdList)) {
if (CollectionUtils.isEmpty(stationIdList)) {
stationIdList = Lists.newArrayList();
}
stationIdList.addAll(queryStationIdList);
}
}
// 站点不为空拿到站点下所有的充电桩id
if (CollectionUtils.isNotEmpty(stationIdList)) {
List<PileDetailVO> pileInfoVOS = pileBasicInfoService.selectPileListByStationIds(stationIdList);
if (CollectionUtils.isNotEmpty(pileInfoVOS)) {
pileSns.addAll(pileInfoVOS.stream().map(PileDetailVO::getPileSn).collect(Collectors.toList()));
}
}
// 通过充电桩id查询
if (CollectionUtils.isNotEmpty(dto.getPileIds())) {
// 批量查
List<PileBasicInfo> pileList = pileBasicInfoMapper.selectByIdList(dto.getPileIds());
if (CollectionUtils.isNotEmpty(pileList)) {
pileSns.addAll(pileList.stream().map(PileBasicInfo::getSn).collect(Collectors.toList()));
}
}
if (CollectionUtils.isEmpty(pileSns) && CollectionUtils.isEmpty(connectorIds) && CollectionUtils.isEmpty(connectorCodeList)) {
return Lists.newArrayList();
}
PageHelper.startPage(pageNum, pageSize);
List<PileConnectorInfoVO> pileConnectorInfoList = pileConnectorInfoMapper.getPileConnectorInfoList(pileSns, connectorIds, connectorCodeList);
// 查询枪口当前订单
for (PileConnectorInfoVO pileConnectorInfoVO : pileConnectorInfoList) {
String pileConnectorCode = pileConnectorInfoVO.getPileConnectorCode();
pileConnectorInfoVO.setConnectorQrCodeUrl(getPileConnectorQrCodeUrl(pileConnectorCode)); // 枪口号二维码
OrderBasicInfo order = orderBasicInfoService.queryChargingByPileConnectorCode(pileConnectorCode);
if (order != null) {
pileConnectorInfoVO.setOrderCode(order.getOrderCode());
}
}
queryRealTimeData(pileConnectorInfoList);
return pileConnectorInfoList;
}
/**
* 充电桩枪口的二维码
* @param pileConnectorCode 枪口编号 如枪口编号为空,则返回前缀 https://api.jsowellcloud.com/app-xcx-h5/pile/connectorDetail/
* @return
*/
@Override
public String getPileConnectorQrCodeUrl(String pileConnectorCode) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(QRCODE_URL_PREFIX);
stringBuilder.append("/app-xcx-h5/pile/connectorDetail/");
if (StringUtils.isNotBlank(pileConnectorCode)) {
if (!stringBuilder.toString().endsWith("/")) {
stringBuilder.append("/");
}
stringBuilder.append(pileConnectorCode);
}
return stringBuilder.toString();
}
/**
* uniapp通过入参查询枪口数据
*
* @param dto
* @return
*/
@Override
public PageResponse getUniAppConnectorInfoListByParams(QueryConnectorListDTO dto) {
int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum();
int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize();
List<String> pileSns = Lists.newArrayList();
List<Long> connectorIds = dto.getConnectorIdList();
List<Long> stationIdList = dto.getStationIdList();
List<String> connectorCodeList = dto.getConnectorCodeList();
// 通过运营商查询站点
if (StringUtils.isNotBlank(dto.getMerchantId())) {
// 查询站点idList
List<Long> queryStationIdList = Lists.newArrayList();
if (CollectionUtils.isNotEmpty(queryStationIdList)) {
if (CollectionUtils.isEmpty(stationIdList)) {
stationIdList = Lists.newArrayList();
}
stationIdList.addAll(queryStationIdList);
}
}
// 站点不为空拿到站点下所有的充电桩id
if (CollectionUtils.isNotEmpty(stationIdList)) {
List<PileDetailVO> pileInfoVOS = pileBasicInfoService.selectPileListByStationIds(stationIdList);
if (CollectionUtils.isNotEmpty(pileInfoVOS)) {
pileSns.addAll(pileInfoVOS.stream().map(PileDetailVO::getPileSn).collect(Collectors.toList()));
}
}
// 通过充电桩id查询
if (CollectionUtils.isNotEmpty(dto.getPileIds())) {
// 批量查
List<PileBasicInfo> pileList = pileBasicInfoMapper.selectByIdList(dto.getPileIds());
if (CollectionUtils.isNotEmpty(pileList)) {
pileSns.addAll(pileList.stream().map(PileBasicInfo::getSn).collect(Collectors.toList()));
}
}
if (CollectionUtils.isEmpty(pileSns) && CollectionUtils.isEmpty(connectorIds) && CollectionUtils.isEmpty(connectorCodeList)) {
return new PageResponse();
}
// 分页
PageHelper.startPage(pageNum, pageSize);
List<PileConnectorInfoVO> pileConnectorInfoList = pileConnectorInfoMapper.getPileConnectorInfoList(pileSns, connectorIds, connectorCodeList);
PageInfo<PileConnectorInfoVO> pageInfo = new PageInfo<>(pileConnectorInfoList);
queryRealTimeData(pageInfo.getList());
// 返回结果集
PageResponse pageResponse = PageResponse.builder()
.pageNum(pageNum)
.pageSize(pageSize)
.list(pageInfo.getList())
.pages(pageInfo.getPages())
.total(pageInfo.getTotal())
.build();
return pageResponse;
}
/**
* uniApp通过站点id查询枪口列表信息
*
* @param stationId 站点id
* @return
*/
@Override
public List<ConnectorInfoVO> getUniAppConnectorList(Long stationId) {
// TODO 加缓存
return pileConnectorInfoMapper.getUniAppConnectorList(stationId);
}
@Override
public List<ConnectorInfoVO> selectConnectorInfoList(String pileSn) {
// 查询充电桩型号信息
PileModelInfoVO pileModelInfoVO = pileModelInfoService.getPileModelInfoByPileSn(pileSn);
List<PileConnectorInfo> connectorList = selectPileConnectorInfoList(pileSn);
List<ConnectorInfoVO> connectorInfoList = Lists.newArrayList();
if (CollectionUtils.isNotEmpty(connectorList)) {
for (PileConnectorInfo connectorInfo : connectorList) {
ConnectorInfoVO infoVO = ConnectorInfoVO.builder()
.connectorCode(StringUtils.replace(connectorInfo.getPileConnectorCode(), pileSn, ""))
.pileConnectorCode(connectorInfo.getPileConnectorCode())
.connectorStatus(connectorInfo.getStatus())
.build();
if (pileModelInfoVO != null) {
infoVO.setChargingType(pileModelInfoVO.getSpeedType());
infoVO.setRatedPower(pileModelInfoVO.getRatedPower());
}
connectorInfoList.add(infoVO);
}
}
return connectorInfoList;
}
/**
* 查询充电枪口的实时数据
*/
private void queryRealTimeData(List<PileConnectorInfoVO> pileConnectorInfoList) {
if (CollectionUtils.isEmpty(pileConnectorInfoList)) {
return;
}
// 获取枪口的日志记录
for (PileConnectorInfoVO pileConnectorInfoVO : pileConnectorInfoList) {
// 从redis中获取实时数据信息
if (StringUtils.isNotBlank(pileConnectorInfoVO.getOrderCode())) {
List<RealTimeMonitorData> chargingRealTimeDataList = orderBasicInfoService.getChargingRealTimeData(pileConnectorInfoVO.getOrderCode());
RealTimeMonitorData realTimeMonitorData = chargingRealTimeDataList.get(0);
BigDecimal outputVoltage = new BigDecimal(realTimeMonitorData.getOutputVoltage());
pileConnectorInfoVO.setVoltage(outputVoltage);
BigDecimal outputCurrent = new BigDecimal(realTimeMonitorData.getOutputCurrent());
pileConnectorInfoVO.setCurrent(outputCurrent);
pileConnectorInfoVO.setSOC(realTimeMonitorData.getSOC()); // 充电百分比
pileConnectorInfoVO.setChargingAmount(new BigDecimal(realTimeMonitorData.getChargingAmount()));
pileConnectorInfoVO.setChargingDegree(new BigDecimal(realTimeMonitorData.getChargingDegree()));
pileConnectorInfoVO.setGunLineTemperature(realTimeMonitorData.getGunLineTemperature()); // 枪线温度
pileConnectorInfoVO.setTimeRemaining(realTimeMonitorData.getTimeRemaining());
pileConnectorInfoVO.setChargingTime(realTimeMonitorData.getSumChargingTime());
// 计算实时功率单位kw
BigDecimal instantPowerTemp = outputVoltage.multiply(outputCurrent);
BigDecimal instantPower = instantPowerTemp.divide(new BigDecimal(1000));
pileConnectorInfoVO.setInstantPower(instantPower.setScale(2, BigDecimal.ROUND_HALF_UP));
log.info("枪口实时数据:{}", JSONObject.toJSONString(pileConnectorInfoVO));
}
if (checkPileOffLine(pileConnectorInfoVO.getPileSn())) {
// 最后收到消息的时间在1分钟前则返回给前端枪口离线
pileConnectorInfoVO.setStatus(Integer.valueOf(PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue()));
// 并修改数据库状态为离线
updateConnectorStatusByPileSn(pileConnectorInfoVO.getPileSn(), PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue());
}
}
}
/**
* 通过桩编号修改枪口状态
* 仅用于登录逻辑使用
*
* @param pileSn 充电桩编号
* @param status 充电桩枪口状态
*/
public int updateConnectorStatusByPileSn(String pileSn, String status) {
if (StringUtils.isBlank(pileSn) || StringUtils.isBlank(status)) {
return 0;
}
// 通过pileSn查询枪口列表
List<PileConnectorInfo> connectorInfoList = selectPileConnectorInfoList(pileSn);
if (CollectionUtils.isEmpty(connectorInfoList)) {
return 0;
}
int i = 0;
for (PileConnectorInfo connectorInfo : connectorInfoList) {
i = i + updateConnectorStatus(connectorInfo.getPileConnectorCode(), status);
}
return i;
}
/**
* 修改枪口状态
* 所有修改枪口状态的都要使用这个方法,和数据库交互只有这一个口子
*
* @param connectorCode 枪口号 桩编号+枪口号
* @param status 状态 0离网 (默认)1空闲2占用未充电3占用充电中4占用预约锁定 255故障
*/
@Override
public int updateConnectorStatus(String connectorCode, String status) {
int num = 0;
if (StringUtils.isBlank(connectorCode) || StringUtils.isBlank(status)) {
return num;
}
String redisKey = CacheConstants.PILE_CONNECTOR_STATUS_KEY + connectorCode;
String redisStatus = redisCache.getCacheObject(redisKey);
// log.info("修改充电桩枪口状态 缓存状态:{}, 传来的状态:{}", redisStatus, status);
if (!StringUtils.equals(redisStatus, status)) {
log.info("更新枪口状态 枪口号:{}, 缓存状态:{}, 状态值:{}, 状态:{}", connectorCode, redisStatus, status, PileConnectorDataBaseStatusEnum.getStatusDescription(status));
String pileSn = connectorCode.substring(0, connectorCode.length() - 2);
// 只修改一个枪口的状态
num = pileConnectorInfoMapper.updateConnectorStatus(connectorCode, status);
deleteRedisByPileSn(pileSn);
redisCache.setCacheObject(redisKey, status);
}
return num;
}
/**
* 批量获取桩状态
* 桩的状态有 在线 离线 故障
*
* @param pileSnList 桩编号列表
* @return key:桩编号; value:状态
*/
@Override
public Map<String, String> getPileStatus(List<String> pileSnList) {
Map<String, String> resultMap = Maps.newHashMap();
for (String pileSn : pileSnList) {
String pileStatus = "";
// 标识桩故障或者离线
boolean flag = false;
// 判断故障状态
List<PileConnectorInfo> connectorList = selectPileConnectorInfoList(pileSn); // 获取枪口信息
List<String> connectorStatusList = connectorList.stream().map(PileConnectorInfo::getStatus).collect(Collectors.toList());
// 桩下面的枪口,任意一个故障,桩的状态就是故障
if (connectorStatusList.contains(PileConnectorDataBaseStatusEnum.FAULT.getValue())) {
pileStatus = PileStatusEnum.FAULT.getValue();
flag = true;
}
// 判断离线状态 显示优先级 离线>故障
// if (checkPileOffLine(pileSn)) {
// pileStatus = PileStatusEnum.OFF_LINE.getValue();
// flag = true;
// }
// 2023年1月10日11点32分 改成如果枪口离线,那么充电桩就是离线
if (connectorStatusList.contains(PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue())) {
pileStatus = PileStatusEnum.OFF_LINE.getValue();
flag = true;
}
// 没有故障或者离线,就是在线状态
if (!flag) {
pileStatus = PileStatusEnum.ON_LINE.getValue();
}
resultMap.put(pileSn, pileStatus);
}
return resultMap;
}
@Override
public PileConnectorInfoVO getPileConnectorInfoByConnectorCode(String pileConnectorCode) {
return pileConnectorInfoMapper.getPileConnectorInfoByConnectorCode(pileConnectorCode);
}
/**
* 判断充电桩是否离线
*
* @param pileSn 桩编号
* @return true离线
*/
private boolean checkPileOffLine(String pileSn) {
// 获取桩最后连接时间最后连接到平台的时间在1分钟之前判定为离线
String lastConnectionTime = redisCache.getCacheObject(CacheConstants.PILE_LAST_CONNECTION + pileSn);
if (StringUtils.isBlank(lastConnectionTime)) {
// 没有最后连接时间,返回离线
return true;
}
long l = DateUtils.intervalTime(lastConnectionTime, DateUtils.getTime());
return l >= 1L;
}
}

View File

@@ -0,0 +1,108 @@
package com.jsowell.pile.service.impl;
import com.google.common.collect.Lists;
import com.jsowell.common.util.DateUtils;
import com.jsowell.pile.domain.PileLicenceInfo;
import com.jsowell.pile.mapper.PileLicenceInfoMapper;
import com.jsowell.pile.service.IPileLicenceInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 充电桩证书信息Service业务层处理
*
* @author jsowell
* @date 2022-08-27
*/
@Service
public class PileLicenceInfoServiceImpl implements IPileLicenceInfoService
{
@Autowired
private PileLicenceInfoMapper pileLicenceInfoMapper;
/**
* 查询充电桩证书信息
*
* @param id 充电桩证书信息主键
* @return 充电桩证书信息
*/
@Override
public PileLicenceInfo selectPileLicenceInfoById(Long id)
{
return pileLicenceInfoMapper.selectPileLicenceInfoById(id);
}
public static void main(String[] args) {
String applyTime = "00:00-05:00,10:00-13:00,10:00-13:00,10:00-13:00";
List<String> timeList = Lists.newArrayList(applyTime.split(","));
System.out.println(timeList);
for (String s : timeList) {
System.out.println(s);
}
}
/**
* 查询充电桩证书信息列表
*
* @param pileLicenceInfo 充电桩证书信息
* @return 充电桩证书信息
*/
@Override
public List<PileLicenceInfo> selectPileLicenceInfoList(PileLicenceInfo pileLicenceInfo)
{
return pileLicenceInfoMapper.selectPileLicenceInfoList(pileLicenceInfo);
}
/**
* 新增充电桩证书信息
*
* @param pileLicenceInfo 充电桩证书信息
* @return 结果
*/
@Override
public int insertPileLicenceInfo(PileLicenceInfo pileLicenceInfo)
{
pileLicenceInfo.setCreateTime(DateUtils.getNowDate());
return pileLicenceInfoMapper.insertPileLicenceInfo(pileLicenceInfo);
}
/**
* 修改充电桩证书信息
*
* @param pileLicenceInfo 充电桩证书信息
* @return 结果
*/
@Override
public int updatePileLicenceInfo(PileLicenceInfo pileLicenceInfo)
{
pileLicenceInfo.setUpdateTime(DateUtils.getNowDate());
return pileLicenceInfoMapper.updatePileLicenceInfo(pileLicenceInfo);
}
/**
* 批量删除充电桩证书信息
*
* @param ids 需要删除的充电桩证书信息主键
* @return 结果
*/
@Override
public int deletePileLicenceInfoByIds(Long[] ids)
{
return pileLicenceInfoMapper.deletePileLicenceInfoByIds(ids);
}
/**
* 删除充电桩证书信息信息
*
* @param id 充电桩证书信息主键
* @return 结果
*/
@Override
public int deletePileLicenceInfoById(Long id)
{
return pileLicenceInfoMapper.deletePileLicenceInfoById(id);
}
}

View File

@@ -0,0 +1,118 @@
package com.jsowell.pile.service.impl;
import com.google.common.collect.Lists;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.PileMemberRelation;
import com.jsowell.pile.mapper.PileMemberRelationMapper;
import com.jsowell.pile.service.IPileConnectorInfoService;
import com.jsowell.pile.service.IPileMemberRelationService;
import com.jsowell.pile.vo.uniapp.PersonalPileInfoVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 桩与用户绑定关系Service业务层处理
*
* @author jsowell
* @date 2023-02-21
*/
@Service
public class PileMemberRelationServiceImpl implements IPileMemberRelationService {
@Autowired
private PileMemberRelationMapper pileMemberRelationMapper;
@Autowired
private IPileConnectorInfoService pileConnectorInfoService;
/**
* 查询桩与用户绑定关系
*
* @param id 桩与用户绑定关系主键
* @return 桩与用户绑定关系
*/
@Override
public PileMemberRelation selectPileMemberRelationById(Integer id) {
return pileMemberRelationMapper.selectPileMemberRelationById(id);
}
/**
* 查询桩与用户绑定关系列表
*
* @param pileMemberRelation 桩与用户绑定关系
* @return 桩与用户绑定关系
*/
@Override
public List<PileMemberRelation> selectPileMemberRelationList(PileMemberRelation pileMemberRelation) {
return pileMemberRelationMapper.selectPileMemberRelationList(pileMemberRelation);
}
/**
* 条件查询桩与用户绑定关系
*
* @param pileMemberRelation 桩与用户绑定关系
* @return 桩与用户绑定关系对象
*/
@Override
public PileMemberRelation selectPileMemberRelation(PileMemberRelation pileMemberRelation) {
return pileMemberRelationMapper.selectPileMemberRelation(pileMemberRelation);
}
/**
* 新增桩与用户绑定关系
*
* @param pileMemberRelation 桩与用户绑定关系
* @return 结果
*/
@Override
public int insertPileMemberRelation(PileMemberRelation pileMemberRelation) {
pileMemberRelation.setCreateTime(DateUtils.getNowDate());
return pileMemberRelationMapper.insertPileMemberRelation(pileMemberRelation);
}
/**
* 修改桩与用户绑定关系
*
* @param pileMemberRelation 桩与用户绑定关系
* @return 结果
*/
@Override
public int updatePileMemberRelation(PileMemberRelation pileMemberRelation) {
return pileMemberRelationMapper.updatePileMemberRelation(pileMemberRelation);
}
/**
* 批量删除桩与用户绑定关系
*
* @param ids 需要删除的桩与用户绑定关系主键
* @return 结果
*/
@Override
public int deletePileMemberRelationByIds(Integer[] ids) {
return pileMemberRelationMapper.deletePileMemberRelationByIds(ids);
}
/**
* 删除桩与用户绑定关系信息
*
* @param id 桩与用户绑定关系主键
* @return 结果
*/
@Override
public int deletePileMemberRelationById(Integer id) {
return pileMemberRelationMapper.deletePileMemberRelationById(id);
}
@Override
public List<PileMemberRelation> selectPileMemberRelationByPileSn(String pileSn) {
PileMemberRelation pileMemberRelation = new PileMemberRelation();
pileMemberRelation.setPileSn(pileSn);
return selectPileMemberRelationList(pileMemberRelation);
}
}

View File

@@ -0,0 +1,167 @@
package com.jsowell.pile.service.impl;
import com.jsowell.common.annotation.DataScope;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.entity.SysDept;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.DictUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.PileMerchantInfo;
import com.jsowell.pile.mapper.PileMerchantInfoMapper;
import com.jsowell.pile.service.IPileMerchantInfoService;
import com.jsowell.pile.vo.base.MerchantInfoVO;
import com.jsowell.system.service.SysDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
/**
* 充电桩运营商信息Service业务层处理
*
* @author jsowell
* @date 2022-08-27
*/
@Slf4j
@Service
public class PileMerchantInfoServiceImpl implements IPileMerchantInfoService {
@Autowired
private PileMerchantInfoMapper pileMerchantInfoMapper;
@Autowired
private SysDeptService sysDeptService;
@Value("${weixin.login.appid}")
private String appid;
/**
* 查询充电桩运营商信息
*
* @param id 充电桩运营商信息主键
* @return 充电桩运营商信息
*/
@Override
public PileMerchantInfo selectPileMerchantInfoById(Long id) {
return pileMerchantInfoMapper.selectPileMerchantInfoById(id);
}
/**
* 查询充电桩运营商信息列表
*
* @param pileMerchantInfo 充电桩运营商信息
* @return 充电桩运营商信息
*/
@Override
@DataScope(deptAlias = "t")
public List<PileMerchantInfo> selectPileMerchantInfoList(PileMerchantInfo pileMerchantInfo) {
List<PileMerchantInfo> list = pileMerchantInfoMapper.selectPileMerchantInfoList(pileMerchantInfo);
if (Objects.nonNull(list)) {
for (PileMerchantInfo p:list) {
String status = p.getStatus();
String merchant_status = DictUtils.getDictLabel("merchant_status", status);
p.setStatus(merchant_status);
}
}
return list;
}
/**
* 新增充电桩运营商信息
*
* @param pileMerchantInfo 充电桩运营商信息
* @return 结果
*/
@Override
@Transactional
public int insertPileMerchantInfo(PileMerchantInfo pileMerchantInfo) {
// 1. 新增sys_dept
SysDept dept = new SysDept();
dept.setParentId(100L);
dept.setOrderNum(0);
dept.setDeptName(pileMerchantInfo.getMerchantName());
dept.setLeader(pileMerchantInfo.getManagerName());
dept.setPhone(pileMerchantInfo.getManagerPhone());
dept.setStatus("0");
sysDeptService.insertDept(dept);
// 2. 新增pile_merchant_info
Long deptId = dept.getDeptId();
// pileMerchantInfo.setId(deptId);
pileMerchantInfo.setDeptId(String.valueOf(deptId));
pileMerchantInfo.setStatus(Constants.ONE);
String appId = StringUtils.isBlank(pileMerchantInfo.getAppId())
? appid
: pileMerchantInfo.getAppId();
pileMerchantInfo.setAppId(appId);
return pileMerchantInfoMapper.insertPileMerchantInfo(pileMerchantInfo);
}
/**
* 修改充电桩运营商信息
*
* @param pileMerchantInfo 充电桩运营商信息
* @return 结果
*/
@Override
public int updatePileMerchantInfo(PileMerchantInfo pileMerchantInfo) {
pileMerchantInfo.setUpdateTime(DateUtils.getNowDate());
return pileMerchantInfoMapper.updatePileMerchantInfo(pileMerchantInfo);
}
/**
* 批量删除充电桩运营商信息
*
* @param ids 需要删除的充电桩运营商信息主键
* @return 结果
*/
@Override
public int deletePileMerchantInfoByIds(Long[] ids) {
return pileMerchantInfoMapper.deletePileMerchantInfoByIds(ids);
}
/**
* 删除充电桩运营商信息信息
*
* @param id 充电桩运营商信息主键
* @return 结果
*/
@Override
public int deletePileMerchantInfoById(Long id) {
return pileMerchantInfoMapper.deletePileMerchantInfoById(id);
}
@Override
public String getMerchantIdByAppId(String appId) {
if (StringUtils.isBlank(appId)) {
return null;
}
try {
PileMerchantInfo pileMerchantInfo = pileMerchantInfoMapper.selectPileMerchantInfoByAppId(appId);
if (pileMerchantInfo != null) {
return pileMerchantInfo.getId().toString();
}
} catch (Exception e) {
log.error("通过appid获取运营商id error", e);
}
return null;
}
@Override
public MerchantInfoVO getMerchantInfo(String merchantId) {
PileMerchantInfo pileMerchantInfo = selectPileMerchantInfoById(Long.parseLong(merchantId));
if (pileMerchantInfo == null) {
return null;
}
MerchantInfoVO vo = MerchantInfoVO.builder()
.merchantId(merchantId)
.merchantName(pileMerchantInfo.getMerchantName())
.merchantTel(pileMerchantInfo.getServicePhone())
.deptId(pileMerchantInfo.getDeptId())
.build();
return vo;
}
}

View File

@@ -0,0 +1,113 @@
package com.jsowell.pile.service.impl;
import com.google.common.collect.Lists;
import com.jsowell.common.util.DateUtils;
import com.jsowell.pile.domain.PileModelInfo;
import com.jsowell.pile.mapper.PileModelInfoMapper;
import com.jsowell.pile.service.IPileModelInfoService;
import com.jsowell.pile.vo.web.PileModelInfoVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 充电桩型号信息Service业务层处理
*
* @author jsowell
* @date 2022-08-26
*/
@Service
public class PileModelInfoServiceImpl implements IPileModelInfoService {
@Autowired
private PileModelInfoMapper pileModelInfoMapper;
/**
* 查询充电桩型号信息
*
* @param id 充电桩型号信息主键
* @return 充电桩型号信息
*/
@Override
public PileModelInfo selectPileModelInfoById(Long id) {
return pileModelInfoMapper.selectPileModelInfoById(id);
}
/**
* 查询充电桩型号信息列表
*
* @param pileModelInfo 充电桩型号信息
* @return 充电桩型号信息
*/
@Override
public List<PileModelInfo> selectPileModelInfoList(PileModelInfo pileModelInfo) {
return pileModelInfoMapper.selectPileModelInfoList(pileModelInfo);
}
/**
* 新增充电桩型号信息
*
* @param pileModelInfo 充电桩型号信息
* @return 结果
*/
@Override
public int insertPileModelInfo(PileModelInfo pileModelInfo) {
pileModelInfo.setCreateTime(DateUtils.getNowDate());
return pileModelInfoMapper.insertPileModelInfo(pileModelInfo);
}
/**
* 修改充电桩型号信息
*
* @param pileModelInfo 充电桩型号信息
* @return 结果
*/
@Override
public int updatePileModelInfo(PileModelInfo pileModelInfo) {
pileModelInfo.setUpdateTime(DateUtils.getNowDate());
return pileModelInfoMapper.updatePileModelInfo(pileModelInfo);
}
/**
* 批量删除充电桩型号信息
*
* @param ids 需要删除的充电桩型号信息主键
* @return 结果
*/
@Override
public int deletePileModelInfoByIds(Long[] ids) {
return pileModelInfoMapper.deletePileModelInfoByIds(ids);
}
/**
* 删除充电桩型号信息信息
*
* @param id 充电桩型号信息主键
* @return 结果
*/
@Override
public int deletePileModelInfoById(Long id) {
return pileModelInfoMapper.deletePileModelInfoById(id);
}
/**
* 通过桩编号集合获取型号表中数据
*
* @param pileSns 桩编号集合
* @return PileModelInfo对象
*/
@Override
public List<PileModelInfoVO> getPileModelInfoByPileSnList(List<String> pileSns) {
return pileModelInfoMapper.getPileModelInfoByPileSnList(pileSns);
}
@Override
public PileModelInfoVO getPileModelInfoByPileSn(String pileSn) {
List<PileModelInfoVO> list = getPileModelInfoByPileSnList(Lists.newArrayList(pileSn));
if (CollectionUtils.isNotEmpty(list)) {
return list.get(0);
}
return null;
}
}

View File

@@ -0,0 +1,109 @@
package com.jsowell.pile.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
import com.jsowell.common.core.page.PageResponse;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.pile.domain.PileMsgRecord;
import com.jsowell.pile.dto.QueryPileDTO;
import com.jsowell.pile.mapper.PileMsgRecordMapper;
import com.jsowell.pile.service.IPileMsgRecordService;
import com.jsowell.pile.vo.web.PileCommunicationLogVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class PileMsgRecordServiceImpl implements IPileMsgRecordService {
@Autowired
private PileMsgRecordMapper pileMsgRecordMapper;
@Override
public void save(String pileSn, String connectorCode, String frameType, String jsonMsg, String originalMsg) {
PileMsgRecord pileMsgRecord = PileMsgRecord.builder()
.pileSn(pileSn)
.connectorCode(connectorCode)
.jsonMsg(jsonMsg)
.frameType(frameType)
.originalMsg(originalMsg)
.build();
pileMsgRecordMapper.insertSelective(pileMsgRecord);
}
// @Override
// public List<PileMsgRecord> getByConnectorCodeList(List<String> connectorCodeList) {
// if (CollectionUtils.isEmpty(connectorCodeList)) {
// return Lists.newArrayList();
// }
// return pileMsgRecordMapper.getByConnectorCodeList(connectorCodeList);
// }
public static void main(String[] args) {
String type = BytesUtil.bcd2Str(YKCFrameTypeCode.TRANSACTION_RECORDS_CODE.getBytes());
System.out.println(type);
String binary = BytesUtil.binary(YKCFrameTypeCode.TRANSACTION_RECORDS_CODE.getBytes(), 16);
System.out.println(binary);
String s = YKCUtils.frameType2Str(YKCFrameTypeCode.TRANSACTION_RECORDS_CODE.getBytes());
System.out.println(s);
}
@Override
public PageResponse getPileFeedList(QueryPileDTO dto) {
// 分页
PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
List<PileMsgRecord> pileFeedList = pileMsgRecordMapper.getPileFeedList(dto.getPileSn());
PageInfo<PileMsgRecord> pageInfo = new PageInfo<>(pileFeedList);
List<PileCommunicationLogVO> list = new ArrayList<>();
for (PileMsgRecord pileMsgRecord : pageInfo.getList()) {
PileCommunicationLogVO vo = new PileCommunicationLogVO();
String frameType = pileMsgRecord.getFrameType();
String frameTypeStr = YKCFrameTypeCode.getFrameTypeStr(frameType);
if (StringUtils.isNotBlank(frameTypeStr)) {
vo.setDescription(frameTypeStr);
} else {
vo.setDescription(pileMsgRecord.getJsonMsg());
}
// if (StringUtils.equals(YKCUtils.frameType2Str(YKCFrameTypeCode.LOGIN_CODE.getBytes()), frameType)) {
// // 登录
// vo.setDescription("充电桩登录认证");
// } else if (StringUtils.equals(YKCUtils.frameType2Str(YKCFrameTypeCode.REMOTE_RESTART_CODE.getBytes()), frameType)) {
// // 远程重启
// vo.setDescription("远程重启");
// } else if (StringUtils.equals(YKCUtils.frameType2Str(YKCFrameTypeCode.REMOTE_CONTROL_START_CODE.getBytes()), frameType)) {
// // 远程启动充电
// vo.setDescription("运营平台远程控制启机");
// }else if (StringUtils.equals(YKCUtils.frameType2Str(YKCFrameTypeCode.REMOTE_STOP_CHARGING_CODE.getBytes()), frameType)) {
// // 远程停机
// vo.setDescription("运营平台远程停机");
// }else if (StringUtils.equals(YKCUtils.frameType2Str(YKCFrameTypeCode.TRANSACTION_RECORDS_CODE.getBytes()), frameType)) {
// // 交易记录
// vo.setDescription("交易结算");
// }else if (StringUtils.equals(YKCUtils.frameType2Str(YKCFrameTypeCode.PILE_LOG_OUT.getBytes()), frameType)) {
// // 退出
// vo.setDescription("充电桩退出");
// }
vo.setPileSn(pileMsgRecord.getPileSn());
vo.setCreateTime(pileMsgRecord.getCreateTime());
vo.setFrameType(frameType);
list.add(vo);
}
PageResponse pageResponse = PageResponse.builder()
.pageNum(pageInfo.getPageNum())
.pageSize(pageInfo.getPageSize())
.list(list)
.total(pageInfo.getTotal())
.pages(pageInfo.getPages())
.build();
return pageResponse;
}
}

View File

@@ -0,0 +1,137 @@
package com.jsowell.pile.service.impl;
import com.alibaba.fastjson2.JSON;
import com.jsowell.common.util.DateUtils;
import com.jsowell.pile.domain.PileSimInfo;
import com.jsowell.pile.dto.QuerySimInfoDTO;
import com.jsowell.pile.mapper.PileSimInfoMapper;
import com.jsowell.pile.service.IPileSimInfoService;
import com.jsowell.pile.vo.web.SimCardInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 充电桩SIM卡信息Service业务层处理
*
* @author jsowell
* @date 2022-08-26
*/
@Slf4j
@Service
public class PileSimInfoServiceImpl implements IPileSimInfoService {
@Autowired
private PileSimInfoMapper pileSimInfoMapper;
/**
* 查询充电桩SIM卡信息
*
* @param id 充电桩SIM卡信息主键
* @return 充电桩SIM卡信息
*/
@Override
public PileSimInfo selectPileSimInfoById(Long id) {
return pileSimInfoMapper.selectPileSimInfoById(id);
}
/**
* 查询充电桩SIM卡信息列表
*
* @param pileSimInfo 充电桩SIM卡信息
* @return 充电桩SIM卡信息
*/
@Override
public List<PileSimInfo> selectPileSimInfoList(PileSimInfo pileSimInfo) {
return pileSimInfoMapper.selectPileSimInfoList(pileSimInfo);
}
/**
* 后管查询sim卡信息列表
* @return
*/
@Override
public List<SimCardInfoVO> getSimInfoList(QuerySimInfoDTO dto) {
return pileSimInfoMapper.getSimInfoList(dto);
}
/**
* 新增充电桩SIM卡信息
*
* @param pileSimInfo 充电桩SIM卡信息
* @return 结果
*/
@Override
public int insertPileSimInfo(PileSimInfo pileSimInfo) {
pileSimInfo.setCreateTime(DateUtils.getNowDate());
log.info("新增充电桩SIM卡信息 PileSimInfo:{}", JSON.toJSONString(pileSimInfo));
return pileSimInfoMapper.insertPileSimInfo(pileSimInfo);
}
/**
* 修改充电桩SIM卡信息
*
* @param pileSimInfo 充电桩SIM卡信息
* @return 结果
*/
@Override
public int updatePileSimInfo(PileSimInfo pileSimInfo) {
pileSimInfo.setUpdateTime(DateUtils.getNowDate());
return pileSimInfoMapper.updatePileSimInfo(pileSimInfo);
}
/**
* 批量删除充电桩SIM卡信息
*
* @param ids 需要删除的充电桩SIM卡信息主键
* @return 结果
*/
@Override
public int deletePileSimInfoByIds(Long[] ids) {
return pileSimInfoMapper.deletePileSimInfoByIds(ids);
}
/**
* 删除充电桩SIM卡信息信息
*
* @param id 充电桩SIM卡信息主键
* @return 结果
*/
@Override
public int deletePileSimInfoById(Long id) {
return pileSimInfoMapper.deletePileSimInfoById(id);
}
/**
* 通过桩编码查询sim卡信息
*
* @param pileSn 桩编码
* @return
*/
@Override
public SimCardInfoVO querySimCardInfoByPileSn(String pileSn) {
return pileSimInfoMapper.querySimCardInfoByPileSn(pileSn);
}
/**
* 通过卡号批量查询sim卡信息
*
* @param iccIds 卡号
* @return
*/
@Override
public List<PileSimInfo> selectSimInfoByIccIds(List<String> iccIds) {
return pileSimInfoMapper.selectSimInfoByIccIds(iccIds);
}
/**
* 通过卡号查询sim卡信息
*
* @param iccId 卡号
* @return
*/
public PileSimInfo getBasicInfoByIccId(String iccId) {
return pileSimInfoMapper.getBasicInfoByIccId(iccId);
}
}

View File

@@ -0,0 +1,352 @@
package com.jsowell.pile.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.jsowell.common.annotation.DataScope;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.entity.SysDept;
import com.jsowell.common.core.page.PageResponse;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.DistanceUtils;
import com.jsowell.common.util.SecurityUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.ip.AddressUtils;
import com.jsowell.pile.domain.PileStationInfo;
import com.jsowell.pile.dto.FastCreateStationDTO;
import com.jsowell.pile.dto.QueryStationDTO;
import com.jsowell.pile.mapper.PileStationInfoMapper;
import com.jsowell.pile.service.IPileBillingTemplateService;
import com.jsowell.pile.service.IPileConnectorInfoService;
import com.jsowell.pile.service.IPileMerchantInfoService;
import com.jsowell.pile.service.IPileStationInfoService;
import com.jsowell.pile.vo.base.ConnectorInfoVO;
import com.jsowell.pile.vo.base.MerchantInfoVO;
import com.jsowell.pile.vo.base.StationInfoVO;
import com.jsowell.pile.vo.uniapp.CurrentTimePriceDetails;
import com.jsowell.pile.vo.web.PileStationVO;
import com.jsowell.system.service.SysDeptService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* 充电站信息Service业务层处理
*
* @author jsowell
* @date 2022-08-30
*/
@Service
public class PileStationInfoServiceImpl implements IPileStationInfoService {
@Autowired
private PileStationInfoMapper pileStationInfoMapper;
@Autowired
private IPileConnectorInfoService pileConnectorInfoService;
@Autowired
private IPileBillingTemplateService pileBillingTemplateService;
@Autowired
private IPileMerchantInfoService pileMerchantInfoService;
@Autowired
private SysDeptService sysDeptService;
/**
* 查询充电站信息
*
* @param id 充电站信息主键
* @return 充电站信息
*/
@Override
public PileStationInfo selectPileStationInfoById(Long id) {
return pileStationInfoMapper.selectPileStationInfoById(id);
}
/**
* 查询站点基本资料
* @param stationId
* @return
*/
@Override
public PileStationVO getStationInfo(String stationId) {
PileStationVO vo = new PileStationVO();
PileStationInfo pileStationInfo = selectPileStationInfoById(Long.parseLong(stationId));
// 查计费模板
CurrentTimePriceDetails currentTimePriceDetails = pileBillingTemplateService.getCurrentTimePriceDetails(stationId);
if (currentTimePriceDetails != null) {
vo.setElectricityPrice(new BigDecimal(currentTimePriceDetails.getElectricityPrice()));
vo.setServicePrice(new BigDecimal(currentTimePriceDetails.getServicePrice()));
}
if (pileStationInfo != null) {
vo.setMerchantId(pileStationInfo.getMerchantId().toString());
vo.setStationName(pileStationInfo.getStationName());
vo.setId(pileStationInfo.getId().toString());
vo.setAreaCode(pileStationInfo.getAreaCode());
vo.setAddress(pileStationInfo.getAddress());
vo.setMerchantId(pileStationInfo.getMerchantId().toString());
// vo.setMerchantName(pileStationInfo.getmer());
vo.setMerchantAdminName(pileStationInfo.getStationAdminName());
vo.setStationStatus(Integer.parseInt(pileStationInfo.getStationStatus()));
vo.setStationType(pileStationInfo.getStationType());
vo.setCreateTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, pileStationInfo.getCreateTime()));
vo.setStationTel(pileStationInfo.getStationTel());
vo.setMatchCars(pileStationInfo.getMatchCars());
if (StringUtils.isNotBlank(pileStationInfo.getMatchCars())) {
vo.setSelectMatchCars(Lists.newArrayList(pileStationInfo.getMatchCars().split(",")));
}
vo.setStationLat(pileStationInfo.getStationLat());
vo.setStationLng(pileStationInfo.getStationLng());
vo.setConstruction(pileStationInfo.getConstruction());
vo.setBusinessHours(pileStationInfo.getBusinessHours());
// vo.setOrganizationCode(pileStationInfo.getor);
vo.setPublicFlag(pileStationInfo.getPublicFlag());
vo.setOpenFlag(pileStationInfo.getOpenFlag());
}
return vo;
}
/**
* 查询充电站信息列表
*
* @param pileStationInfo 充电站信息
* @return 充电站信息
*/
@Override
public List<PileStationInfo> selectPileStationInfoList(PileStationInfo pileStationInfo) {
return pileStationInfoMapper.selectPileStationInfoList(pileStationInfo);
}
/**
* 通过运营商id查询站点信息
*
* @param merchantId 运营商id
* @return 站点信息列表
*/
@Override
public List<PileStationInfo> selectStationListByMerchantId(Long merchantId) {
return pileStationInfoMapper.selectStationListByMerchantId(merchantId);
}
/**
* 新增充电站信息
*
* @param pileStationInfo 充电站信息
* @return 结果
*/
@Override
public int insertPileStationInfo(PileStationInfo pileStationInfo) {
pileStationInfo.setCreateTime(DateUtils.getNowDate());
pileStationInfo.setCreateBy(SecurityUtils.getUsername());
return pileStationInfoMapper.insertPileStationInfo(pileStationInfo);
}
/**
* 快速建站
* @param dto
* @return
*/
@Override
public int fastCreateStation(FastCreateStationDTO dto) {
MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(dto.getMerchantId());
if (merchantInfo == null) {
return 0;
}
// 1. 新增sys_dept
SysDept dept = new SysDept();
// 根据运营商Id查询到对应的部门id
dept.setParentId(Long.parseLong(merchantInfo.getDeptId()));
dept.setOrderNum(0);
dept.setDeptName(dto.getStationName());
dept.setLeader(dto.getStationAdminName());
dept.setPhone(dto.getStationTel());
dept.setStatus("0");
sysDeptService.insertDept(dept);
PileStationInfo pileStationInfo = new PileStationInfo();
// pileStationInfo.setId(dept.getDeptId());
pileStationInfo.setDeptId(String.valueOf(dept.getDeptId()));
// 前端输入信息
pileStationInfo.setMerchantId(Long.valueOf(dto.getMerchantId()));
pileStationInfo.setStationName(dto.getStationName());
pileStationInfo.setAddress(dto.getAddress());
pileStationInfo.setAreaCode(dto.getAreaCode());
pileStationInfo.setCapacity(BigDecimal.ZERO); // 容量
pileStationInfo.setStationTel(dto.getStationTel());
pileStationInfo.setStationAdminName(dto.getStationAdminName());
// 获取经纬度
Map<String, String> longitudeAndLatitude = AddressUtils.getLongitudeAndLatitude(dto.getAreaCode(), dto.getAddress());
if (longitudeAndLatitude != null) {
pileStationInfo.setStationLng(longitudeAndLatitude.get("lng"));
pileStationInfo.setStationLat(longitudeAndLatitude.get("lat"));
}
pileStationInfo.setCreateBy(SecurityUtils.getUsername());
int i = pileStationInfoMapper.insertPileStationInfo(pileStationInfo);
return i;
}
/**
* 修改充电站信息
*
* @param pileStationInfo 充电站信息
* @return 结果
*/
@Override
public int updatePileStationInfo(PileStationInfo pileStationInfo) {
pileStationInfo.setUpdateBy(SecurityUtils.getUsername());
pileStationInfo.setUpdateTime(DateUtils.getNowDate());
return pileStationInfoMapper.updatePileStationInfo(pileStationInfo);
}
/**
* 批量删除充电站信息
*
* @param ids 需要删除的充电站信息主键
* @return 结果
*/
@Override
public int deletePileStationInfoByIds(Long[] ids) {
return pileStationInfoMapper.deletePileStationInfoByIds(ids);
}
/**
* 充电站列表信息
* @param dto 前台参数
* @return 充电站对象集合
*/
@Override
@DataScope(deptAlias = "t3")
public List<PileStationVO> queryStationInfos(QueryStationDTO dto) {
List<PileStationVO> list = pileStationInfoMapper.queryStationInfos(dto);
// if (Objects.nonNull(list)){
// for (PileStationVO p:list) {
// String station_type = p.getStationType();
// p.setStationType(DictUtils.getDictLabel("station_type", station_type));
// }
// }
return list;
}
/**
* uniApp查询充电站信息并通过经纬度排序
*
* @param dto 前台参数
* @return 充电站对象集合
*/
@Override
public PageResponse uniAppQueryStationInfoList(QueryStationDTO dto) {
int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum();
int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize();
// 小程序站点列表页只展示对外开放的站点
dto.setPublicFlag(Constants.ONE);
// 根据前台参数分页
PageHelper.startPage(pageNum, pageSize);
List<PileStationVO> list = pileStationInfoMapper.queryStationInfos(dto);
PageInfo<PileStationVO> pageInfo = new PageInfo<>(list);
if (CollectionUtils.isEmpty(pageInfo.getList())) {
return PageResponse.builder()
.pageNum(pageInfo.getPageNum())
.pageSize(pageInfo.getPageSize())
.list(Lists.newArrayList())
.pages(pageInfo.getPages())
.total(pageInfo.getTotal())
.build();
}
List<StationInfoVO> stationVOList = Lists.newArrayList();
StationInfoVO stationVO = null;
String stationLng = dto.getStationLng();
String stationLat = dto.getStationLat();
double distance = 0d;
for (PileStationVO pileStationVO : pageInfo.getList()) {
stationVO = new StationInfoVO();
if (StringUtils.isNotEmpty(stationLng) && StringUtils.isNotEmpty(stationLat)) {
try{
// 计算当前经纬度和站点之间的距离
distance = DistanceUtils.getDistance(Double.parseDouble(stationLng), Double.parseDouble(stationLat),
Double.parseDouble(pileStationVO.getStationLng()), Double.parseDouble(pileStationVO.getStationLat()));
// 保留两位小数
stationVO.setDistance(String.format("%.2f", distance));
}catch (Exception e){
stationVO.setDistance("0.00");
}
}
stationVO.setStationId(pileStationVO.getId());
stationVO.setStationName(pileStationVO.getStationName());
stationVO.setStationAddress(pileStationVO.getAddress());
stationVO.setStationLat(pileStationVO.getStationLat());
stationVO.setStationLng(pileStationVO.getStationLng());
// 站点图片
if (StringUtils.isNotBlank(pileStationVO.getPictures())) {
stationVO.setStationImgList(Lists.newArrayList(pileStationVO.getPictures().split(",")));
}
// 枪口数量
int fastTotal = 0;
int fastFree = 0;
int slowTotal = 0;
int slowFree = 0;
List<ConnectorInfoVO> connectorList = pileConnectorInfoService.getUniAppConnectorList(Long.parseLong(pileStationVO.getId()));
for (ConnectorInfoVO connectorVO : connectorList) {
if (StringUtils.equals(connectorVO.getChargingType(), Constants.ONE)) {
// 快充
fastTotal += 1;
if (StringUtils.equals(connectorVO.getConnectorStatus(), Constants.ONE)) {
fastFree += 1;
}
} else {
// 慢充
slowTotal += 1;
if (StringUtils.equals(connectorVO.getConnectorStatus(), Constants.ONE)) {
slowFree += 1;
}
}
}
stationVO.setFastTotal(fastTotal);
stationVO.setFastFree(fastFree);
stationVO.setSlowTotal(slowTotal);
stationVO.setSlowFree(slowFree);
// 查询当前时段电费
CurrentTimePriceDetails currentTimePriceDetails = pileBillingTemplateService.getCurrentTimePriceDetails(stationVO.getStationId());
if (currentTimePriceDetails != null) {
stationVO.setElectricityPrice(currentTimePriceDetails.getElectricityPrice());
stationVO.setServicePrice(currentTimePriceDetails.getServicePrice());
stationVO.setTotalPrice(currentTimePriceDetails.getTotalPrice());
}
stationVOList.add(stationVO);
}
if (distance != 0.00) {
// 对集合按照距离排序,距离小的在前
stationVOList.sort((o1, o2) -> {
Double a = Double.valueOf(o1.getDistance());
Double b = Double.valueOf(o2.getDistance());
return a.compareTo(b);
});
}
// 返回结果集
return PageResponse.builder()
.pageNum(pageInfo.getPageNum())
.pageSize(pageInfo.getPageSize())
.list(stationVOList)
.pages(pageInfo.getPages())
.total(pageInfo.getTotal())
.build();
}
}

View File

@@ -0,0 +1,353 @@
package com.jsowell.pile.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.jsowell.common.enums.MemberWalletEnum;
import com.jsowell.common.enums.ykc.ActionTypeEnum;
import com.jsowell.common.enums.ykc.PayModeEnum;
import com.jsowell.common.enums.ykc.ScenarioEnum;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.id.SnowflakeIdWorker;
import com.jsowell.pile.domain.MemberTransactionRecord;
import com.jsowell.pile.domain.WxpayCallbackRecord;
import com.jsowell.pile.domain.WxpayRefundCallback;
import com.jsowell.pile.dto.PaymentScenarioDTO;
import com.jsowell.pile.dto.WeixinPayDTO;
import com.jsowell.pile.service.IMemberBasicInfoService;
import com.jsowell.pile.service.IMemberTransactionRecordService;
import com.jsowell.pile.service.WechatPayService;
import com.jsowell.pile.service.WxpayCallbackRecordService;
import com.jsowell.pile.service.WxpayRefundCallbackService;
import com.jsowell.pile.vo.web.UpdateMemberBalanceDTO;
import com.jsowell.wxpay.common.WeChatPayParameter;
import com.jsowell.wxpay.response.WechatPayNotifyParameter;
import com.jsowell.wxpay.response.WechatPayNotifyResource;
import com.jsowell.wxpay.response.WechatPayRefundNotifyResource;
import com.jsowell.wxpay.response.WechatPayRefundRequest;
import com.jsowell.wxpay.response.WechatPayRefundResponse;
import com.jsowell.wxpay.utils.AesUtil;
import com.jsowell.wxpay.utils.HttpUtils;
import com.jsowell.wxpay.utils.WechatPayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
/**
* 微信支付
*/
@Slf4j
@Service
public class WechatPayServiceImpl implements WechatPayService {
@Autowired
private WxpayCallbackRecordService wxpayCallbackRecordService;
@Autowired
private WxpayRefundCallbackService wxpayRefundCallbackService;
@Autowired
private IMemberBasicInfoService memberBasicInfoService;
@Autowired
private IMemberTransactionRecordService memberTransactionRecordService;
@Override
public Map<String, Object> weixinPayV3(WeixinPayDTO dto) throws Exception {
String openId = dto.getOpenId();
//封装请求参数
Map<String, Object> paramMap = new HashMap<>();
// 支付的产品(小程序或者公众号,主要需要和微信支付绑定哦)
paramMap.put("appid", WeChatPayParameter.appId);
// 支付的商户号
paramMap.put("mchid", WeChatPayParameter.mchId);
// 商品描述
paramMap.put("description", dto.getDescription());
// 商户订单号
paramMap.put("out_trade_no", SnowflakeIdWorker.getSnowflakeId());
// 交易结束时间
paramMap.put("time_expire", getTimeExpire());
// 附加数据
paramMap.put("attach", dto.getAttach());
// 通知地址
paramMap.put("notify_url", WeChatPayParameter.notifyUrl);
Map<String, Object> amountMap = Maps.newHashMap();
//订单金额 单位分
amountMap.put("total", Integer.parseInt(getMoney(dto.getAmount())));
amountMap.put("currency", "CNY");
paramMap.put("amount", amountMap);
// 设置小程序所需的openid
Map<String, Object> payerMap = Maps.newHashMap();
payerMap.put("openid", openId);
paramMap.put("payer", payerMap);
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(paramMap);
log.info("支付的相关参数是:{}", body);
Map<String, Object> stringObjectMap = HttpUtils.doPostWexin(WeChatPayParameter.unifiedOrderUrlJS, body);
try {
return WechatPayUtils.getTokenWeixin(WeChatPayParameter.appId, String.valueOf(stringObjectMap.get("prepay_id")));
} catch (Exception e) {
log.error("微信支付v3 error", e);
}
return null;
}
/**
* 获取过期时间
* @return
*/
private String getTimeExpire() {
long currentTimeMillis = System.currentTimeMillis();
currentTimeMillis = currentTimeMillis + (30 * 60 * 1000);
return DateUtils.timeStampToRfc3339(currentTimeMillis);
}
/**
* 元转换成分
*
* @param amount
* @return
*/
public static String getMoney(String amount) {
if (amount == null) {
return "";
}
// 金额转化为分为单位
// 处理包含, ¥ 或者$的金额
String currency = amount.replaceAll("\\$|\\¥|\\,", "");
int index = currency.indexOf(".");
int length = currency.length();
Long amLong = 0L;
if (index == -1) {
amLong = Long.valueOf(currency + "00");
} else if (length - index >= 3) {
amLong = Long.valueOf((currency.substring(0, index + 3)).replace(".", ""));
} else if (length - index == 2) {
amLong = Long.valueOf((currency.substring(0, index + 2)).replace(".", "") + 0);
} else {
amLong = Long.valueOf((currency.substring(0, index + 1)).replace(".", "") + "00");
}
return amLong.toString();
}
/**
* 微信支付回调
* @param request
* @param body
* @throws Exception
* @return
*/
@Override
public Map<String, Object> wechatPayCallbackInfo(HttpServletRequest request, WechatPayNotifyParameter body) throws Exception {
Map<String, Object> resultMap = Maps.newHashMap();
//1获取微信支付回调的获取签名信息
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
ObjectMapper objectMapper = new ObjectMapper();
// 2: 开始解析报文体
String data = objectMapper.writeValueAsString(body);
String message = timestamp + "\n" + nonce + "\n" + data + "\n";
//3获取应答签名
String sign = request.getHeader("Wechatpay-Signature");
//4获取平台对应的证书
String serialNo = request.getHeader("Wechatpay-Serial");
if (!WeChatPayParameter.certificateMap.containsKey(serialNo)) {
WeChatPayParameter.certificateMap = WechatPayUtils.refreshCertificate();
}
X509Certificate x509Certificate = WeChatPayParameter.certificateMap.get(serialNo);
if (!WechatPayUtils.verify(x509Certificate, message.getBytes(), sign)) {
throw new IllegalArgumentException("微信支付签名验证失败:" + message);
}
// log.info("签名验证成功");
WechatPayNotifyParameter.Resource resource = body.getResource();
// 5回调报文解密
AesUtil aesUtil = new AesUtil(WeChatPayParameter.v3Key.getBytes());
// 解密后json字符串
String decryptToString = aesUtil.decryptToString(
resource.getAssociated_data().getBytes(),
resource.getNonce().getBytes(),
resource.getCiphertext());
log.info("2-->decryptToString====>{}", decryptToString);
//6获取微信支付返回的信息
WechatPayNotifyResource wechatPayNotifyResource = JSON.parseObject(decryptToString, WechatPayNotifyResource.class);
//7: 支付状态的判断 如果是success就代表支付成功
if (StringUtils.equals(wechatPayNotifyResource.getTrade_state(), "SUCCESS")) {
// 8获取支付的交易单号流水号和附属参数
String out_trade_no = wechatPayNotifyResource.getOut_trade_no();
// 微信支付单号
String transaction_id = wechatPayNotifyResource.getTransaction_id();
String attach = wechatPayNotifyResource.getAttach();
log.info("3-->微信支付成功,商户订单号是:{}, 支付订单号:{}, 附属参数是:{}", out_trade_no, transaction_id, attach);
// 转换附属参数
PaymentScenarioDTO paymentScenarioDTO = JSONObject.parseObject(attach, PaymentScenarioDTO.class);
String type = paymentScenarioDTO.getType();
BigDecimal amount = new BigDecimal(wechatPayNotifyResource.getAmount().getTotal());
if (StringUtils.equals(type, ScenarioEnum.ORDER.getValue())) {
// 1-订单支付
resultMap.put("orderCode", paymentScenarioDTO.getOrderCode());
resultMap.put("memberId", paymentScenarioDTO.getMemberId());
resultMap.put("amount", amount);
resultMap.put("type", type);
} else if (StringUtils.equals(type, ScenarioEnum.BALANCE.getValue())) {
// 2-充值余额
resultMap.put("memberId", paymentScenarioDTO.getMemberId());
resultMap.put("amount", amount);
resultMap.put("type", type);
}
resultMap.put("out_trade_no", out_trade_no);
resultMap.put("transaction_id", transaction_id);
// 保存微信支付记录
WxpayCallbackRecord record = new WxpayCallbackRecord();
record.setPayScenario(type);
record.setMemberId(paymentScenarioDTO.getMemberId());
record.setOrderCode(paymentScenarioDTO.getOrderCode());
record.setOutTradeNo(out_trade_no);
record.setTransactionId(transaction_id);
record.setMchId(wechatPayNotifyResource.getMchid());
record.setAppId(wechatPayNotifyResource.getAppid());
record.setTradeType(wechatPayNotifyResource.getTrade_type());
record.setTradeState(wechatPayNotifyResource.getTrade_state());
record.setTradeStateDesc(wechatPayNotifyResource.getTrade_state_desc());
record.setBankType(wechatPayNotifyResource.getBank_type());
record.setAttach(wechatPayNotifyResource.getAttach());
record.setSuccessTime(DateUtils.toLocalDateTime(wechatPayNotifyResource.getSuccess_time(), DateUtils.RFC3339));
record.setPayerOpenId(wechatPayNotifyResource.getPayer().getOpenid());
record.setPayerTotal(wechatPayNotifyResource.getAmount().getPayer_total());
wxpayCallbackRecordService.insertSelective(record);
}
return resultMap;
}
/**
* 获取微信退款回调信息
*
* @param request
* @param body
* @return
*/
@Override
public Map<String, Object> wechatPayRefundCallbackInfo(HttpServletRequest request, WechatPayNotifyParameter body) throws Exception {
//1获取微信支付回调的获取签名信息
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
ObjectMapper objectMapper = new ObjectMapper();
// 2: 开始解析报文体
String data = objectMapper.writeValueAsString(body);
String message = timestamp + "\n" + nonce + "\n" + data + "\n";
//3获取应答签名
String sign = request.getHeader("Wechatpay-Signature");
//4获取平台对应的证书
String serialNo = request.getHeader("Wechatpay-Serial");
if (!WeChatPayParameter.certificateMap.containsKey(serialNo)) {
WeChatPayParameter.certificateMap = WechatPayUtils.refreshCertificate();
}
X509Certificate x509Certificate = WeChatPayParameter.certificateMap.get(serialNo);
if (!WechatPayUtils.verify(x509Certificate, message.getBytes(), sign)) {
throw new IllegalArgumentException("微信支付签名验证失败:" + message);
}
// log.info("签名验证成功");
WechatPayNotifyParameter.Resource resource = body.getResource();
// 5回调报文解密
AesUtil aesUtil = new AesUtil(WeChatPayParameter.v3Key.getBytes());
// 解密后json字符串
String decryptToString = aesUtil.decryptToString(
resource.getAssociated_data().getBytes(),
resource.getNonce().getBytes(),
resource.getCiphertext());
log.info("微信退款回调信息:{}", decryptToString);
WechatPayRefundNotifyResource refundNotifyResource = JSONObject.parseObject(decryptToString, WechatPayRefundNotifyResource.class);
if (refundNotifyResource == null) {
return null;
}
// 查询原支付信息,获取是订单结算退款还是余额退款
String out_trade_no = refundNotifyResource.getOut_trade_no();
String out_refund_no = refundNotifyResource.getOut_refund_no();
String transaction_id = refundNotifyResource.getTransaction_id();
String refund_id = refundNotifyResource.getRefund_id();
WxpayCallbackRecord wxpayCallbackRecord = wxpayCallbackRecordService.selectByOutTradeNo(out_trade_no);
if (wxpayCallbackRecord == null) {
log.info("查询原支付信息为空 OutTradeNo:{}", out_trade_no);
return null;
}
String memberId = wxpayCallbackRecord.getMemberId();
String orderCode = wxpayCallbackRecord.getOrderCode();
// 退款金额 单位分
int payer_refund = refundNotifyResource.getAmount().getPayer_refund();
// 分转成元
BigDecimal refundAmount = new BigDecimal(payer_refund).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
if (StringUtils.equals(wxpayCallbackRecord.getPayScenario(), ScenarioEnum.BALANCE.getValue())) {
// 这笔支付订单原来是充值余额的,退款成功了,需要扣掉会员的本金金额
UpdateMemberBalanceDTO dto = new UpdateMemberBalanceDTO();
dto.setMemberId(memberId);
dto.setUpdatePrincipalBalance(refundAmount); // 更新会员本金金额,单位元
dto.setType(MemberWalletEnum.TYPE_OUT.getValue());
dto.setSubType(MemberWalletEnum.SUBTYPE_USER_REFUND.getValue());
memberBasicInfoService.updateMemberBalance(dto);
}
// 保存微信退款回调信息
WxpayRefundCallback record = WxpayRefundCallback.builder()
.memberId(memberId)
.orderCode(orderCode)
.outTradeNo(out_trade_no)
.outRefundNo(out_refund_no)
.transactionId(transaction_id)
.mchId(refundNotifyResource.getMchid())
.refundId(refund_id)
.refundStatus(refundNotifyResource.getRefund_status())
.successTime(refundNotifyResource.getSuccess_time())
.userReceivedAccount(refundNotifyResource.getUser_received_account())
.payerTotal(refundNotifyResource.getAmount().getPayer_total() + "")
.payerRefund(payer_refund + "") // 微信支付接收单位分
.amountTotal(refundNotifyResource.getAmount().getTotal() + "")
.amountRefund(refundNotifyResource.getAmount().getRefund() + "")
.build();
wxpayRefundCallbackService.insertSelective(record);
// 余额支付订单 记录会员交易流水
MemberTransactionRecord memberTransactionRecord = MemberTransactionRecord.builder()
.orderCode(orderCode)
.scenarioType(wxpayCallbackRecord.getPayScenario())
.memberId(memberId)
.actionType(ActionTypeEnum.REVERSE.getValue())
.payMode(PayModeEnum.PAYMENT_OF_WECHATPAY.getValue())
.amount(refundAmount) // 记录会员交易流水,单位元
.outTradeNo(out_trade_no)
.transactionId(transaction_id)
.outRefundNo(out_refund_no)
.refundId(refund_id)
.build();
memberTransactionRecordService.insertSelective(memberTransactionRecord);
return null;
}
/**
* 微信支付 申请退款接口
*/
@Override
public WechatPayRefundResponse ApplyForWechatPayRefundV3(WechatPayRefundRequest request) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(request);
log.info("申请退款的相关参数是:{}", body);
Map<String, Object> stringObjectMap = HttpUtils.doPostWexin(WeChatPayParameter.refundJsUrl, body);
log.info("申请退款的返回参数是:{}", stringObjectMap);
return JSON.parseObject(JSON.toJSONString(stringObjectMap), WechatPayRefundResponse.class);
}
}

View File

@@ -0,0 +1,86 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.WxpayCallbackRecord;
import com.jsowell.pile.mapper.WxpayCallbackRecordMapper;
import com.jsowell.pile.service.WxpayCallbackRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
@Slf4j
@Service
public class WxpayCallbackRecordServiceImpl implements WxpayCallbackRecordService {
@Resource
private WxpayCallbackRecordMapper wxpayCallbackRecordMapper;
@Override
public int deleteByPrimaryKey(Integer id) {
return wxpayCallbackRecordMapper.deleteByPrimaryKey(id);
}
@Override
public int insert(WxpayCallbackRecord record) {
return wxpayCallbackRecordMapper.insert(record);
}
@Override
public int insertSelective(WxpayCallbackRecord record) {
return wxpayCallbackRecordMapper.insertSelective(record);
}
@Override
public WxpayCallbackRecord selectByPrimaryKey(Integer id) {
return wxpayCallbackRecordMapper.selectByPrimaryKey(id);
}
@Override
public int updateByPrimaryKeySelective(WxpayCallbackRecord record) {
return wxpayCallbackRecordMapper.updateByPrimaryKeySelective(record);
}
@Override
public int updateByPrimaryKey(WxpayCallbackRecord record) {
return wxpayCallbackRecordMapper.updateByPrimaryKey(record);
}
@Override
public WxpayCallbackRecord selectByOrderCode(String orderCode) {
WxpayCallbackRecord wxpayCallbackRecord = null;
try {
wxpayCallbackRecord = wxpayCallbackRecordMapper.selectByOrderCode(orderCode);
} catch (Exception e) {
log.error("根据订单号查询微信支付记录:{}", orderCode, e);
}
return wxpayCallbackRecord;
}
@Override
public WxpayCallbackRecord selectByOutTradeNo(String outTradeNo) {
return wxpayCallbackRecordMapper.selectByOutTradeNo(outTradeNo);
}
@Override
public List<WxpayCallbackRecord> queryBalanceRechargeRecordOfTheLatestYear(String memberId) {
LocalDateTime now = LocalDateTime.now();
LocalDate localDate = now.minusYears(1).toLocalDate();
LocalTime localTime = now.toLocalTime();
LocalDateTime lastYear = LocalDateTime.of(localDate, localTime);
// 查询最近一年的余额充值记录
return wxpayCallbackRecordMapper.selectBalanceRechargeRecord(memberId, lastYear);
}
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDate localDate = now.minusYears(1).toLocalDate();
LocalTime localTime = now.toLocalTime();
LocalDateTime of = LocalDateTime.of(localDate, localTime);
System.out.println(of);
}
}

View File

@@ -0,0 +1,41 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.WxpayRefundCallback;
import com.jsowell.pile.mapper.WxpayRefundCallbackMapper;
import com.jsowell.pile.service.WxpayRefundCallbackService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class WxpayRefundCallbackServiceImpl implements WxpayRefundCallbackService {
@Resource
private WxpayRefundCallbackMapper wxpayRefundCallbackMapper;
@Override
public int deleteByPrimaryKey(Integer id) {
return wxpayRefundCallbackMapper.deleteByPrimaryKey(id);
}
@Override
public int insertSelective(WxpayRefundCallback record) {
return wxpayRefundCallbackMapper.insertSelective(record);
}
@Override
public WxpayRefundCallback selectByPrimaryKey(Integer id) {
return wxpayRefundCallbackMapper.selectByPrimaryKey(id);
}
@Override
public int updateByPrimaryKeySelective(WxpayRefundCallback record) {
return wxpayRefundCallbackMapper.updateByPrimaryKeySelective(record);
}
@Override
public int updateByPrimaryKey(WxpayRefundCallback record) {
return wxpayRefundCallbackMapper.updateByPrimaryKey(record);
}
}