package com.jsowell.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.huifu.adapay.core.AdapayCore; import com.huifu.adapay.core.util.AdapaySign; import com.jsowell.adapay.response.PaymentReverseResponse; import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; import com.jsowell.common.core.domain.vo.AuthorizedDeptVO; import com.jsowell.common.core.domain.ykc.RealTimeMonitorData; import com.jsowell.common.core.domain.ykc.TransactionRecordsData; import com.jsowell.common.core.page.PageResponse; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.AcquirerEnum; import com.jsowell.common.enums.DelFlagEnum; import com.jsowell.common.enums.InvoiceRecordEnum; import com.jsowell.common.enums.MemberWalletEnum; import com.jsowell.common.enums.adapay.AdapayEventEnum; import com.jsowell.common.enums.uniapp.OccupyOrderPayStatusEnum; import com.jsowell.common.enums.uniapp.OccupyOrderStatusEnum; import com.jsowell.common.enums.ykc.*; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.DateUtils; import com.jsowell.common.util.SecurityUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.bean.BeanUtils; import com.jsowell.pile.domain.*; import com.jsowell.pile.dto.*; import com.jsowell.pile.service.*; import com.jsowell.pile.service.orderlogic.AbstractOrderLogic; import com.jsowell.pile.service.orderlogic.OrderLogicFactory; import com.jsowell.pile.vo.base.OrderAmountDetailVO; import com.jsowell.pile.vo.base.OrderPeriodAmountVO; import com.jsowell.pile.vo.base.PileInfoVO; import com.jsowell.pile.vo.base.StationInfoVO; import com.jsowell.pile.vo.uniapp.*; import com.jsowell.pile.vo.web.OrderDetailInfoVO; import com.jsowell.pile.vo.web.PileStationVO; import com.jsowell.pile.vo.web.PlatformTesterVO; import com.jsowell.pile.vo.web.UpdateMemberBalanceDTO; import com.jsowell.wxpay.response.WechatPayNotifyParameter; 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 javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.text.ParseException; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @Service public class OrderService { private final Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private IOrderBasicInfoService orderBasicInfoService; @Autowired private PileRemoteService pileRemoteService; @Autowired private PileService pileService; @Autowired private MemberService memberService; @Autowired private IMemberBasicInfoService memberBasicInfoService; @Autowired private OrderPayRecordService orderPayRecordService; @Autowired private WechatPayService wechatPayService; @Autowired private IMemberTransactionRecordService memberTransactionRecordService; @Autowired private IPileStationInfoService pileStationInfoService; @Autowired private IOrderInvoiceRecordService orderInvoiceRecordService; @Autowired private IPileStationWhitelistService pileStationWhitelistService; @Autowired private AdapayCallbackRecordService adapayCallbackRecordService; @Autowired private IMemberInvoiceTitleService memberInvoiceTitleService; @Autowired private IAdapayRefundRecordService adapayRefundRecordService; @Autowired private IAdapayMemberAccountService adapayMemberAccountService; @Autowired private ClearingWithdrawInfoService clearingWithdrawInfoService; @Autowired private MemberAdapayRecordService memberAdapayRecordService; @Resource private OrderPileOccupyService orderPileOccupyService; @Resource private IPileMerchantInfoService pileMerchantInfoService; @Resource private IMemberWalletLogService memberWalletLogService; @Resource private RedisCache redisCache; /** * 生成订单 * * @param dto * @return */ @Deprecated public String generateOrder(GenerateOrderDTO dto) throws ParseException { OrderBasicInfo basicInfo = orderBasicInfoService.generateOrder(dto); if (basicInfo != null) { return basicInfo.getOrderCode(); } return null; } /** * 生成订单 * * @param dto * @return */ public String generateOrderV2(GenerateOrderDTO dto) throws ParseException { // 新逻辑 String delayMode = pileMerchantInfoService.getDelayModeByWechatAppId(dto.getAppId()); AbstractOrderLogic orderLogic = OrderLogicFactory.getOrderLogic(delayMode); OrderBasicInfo orderBasicInfo = orderLogic.generateOrder(dto); if (orderBasicInfo != null) { return orderBasicInfo.getOrderCode(); } return null; } /** * 订单支付 * * @param dto */ @Deprecated public Map payOrder(PayOrderDTO dto) throws Exception { return orderBasicInfoService.payOrder(dto); } /** * 订单支付 * * @param dto */ public Map payOrderV2(PayOrderDTO dto) { String mode = pileMerchantInfoService.getDelayModeByWechatAppId(dto.getWechatAppId()); // 获取处理逻辑 AbstractOrderLogic orderLogic = OrderLogicFactory.getOrderLogic(mode); Map map = orderLogic.payOrder(dto); return map; } /** * 结算订单 * endCharging * * @param dto 结算订单参数 */ public void settleOrderForWeb(SettleOrderDTO dto) { orderBasicInfoService.analysisPileParameter(dto); // 查询订单详情,验证订单中的桩编号是否正确 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(dto.getOrderCode()); if (orderBasicInfo == null) { throw new BusinessException(ReturnCodeEnum.CODE_QUERY_ORDER_INFO_IS_NULL); } if (!(StringUtils.equals(orderBasicInfo.getPileSn(), dto.getPileSn()) && StringUtils.equals(orderBasicInfo.getConnectorCode(), dto.getConnectorCode()))) { throw new BusinessException(ReturnCodeEnum.CODE_ORDER_PILE_MAPPING_ERROR); } // push远程停机指令 pileRemoteService.remoteStopCharging(dto.getPileSn(), dto.getConnectorCode()); } /** * 通过会员Id查询订单列表 * * @param memberId 会员Id * @return 订单信息集合 */ public PageResponse getListByMemberIdAndOrderStatus(String memberId, UniAppQueryOrderDTO dto) throws ParseException { String orderStatus = dto.getOrderStatus(); if (StringUtils.isBlank(orderStatus)) { throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); } ArrayList orderStatusList = Lists.newArrayList(); if (StringUtils.equals("2", orderStatus)) { // 查未完成订单 CollectionUtils.addAll(orderStatusList, "0", "1", "2", "3", "4", "5"); } else if (StringUtils.equals("3", orderStatus)) { // 查已完成订单 orderStatusList.add("6"); } else if (StringUtils.equals("4", orderStatus)) { // 查询正在进行中的订单 orderStatusList.add("1"); } // 分页 PageHelper.startPage(dto.getPageNum(), dto.getPageSize()); List list = orderBasicInfoService.getListByMemberIdAndOrderStatus(memberId, orderStatusList); PageInfo pageInfo = new PageInfo<>(list); for (OrderVO orderVO : pageInfo.getList()) { orderVO.setPileConnectorCode(orderVO.getPileSn() + orderVO.getConnectorCode()); String chargingTime = "0分钟"; if (orderVO.getStartTime() != null) { Date startTimeDate = DateUtils.parseDate(orderVO.getStartTime()); Date endTimeDate; if (orderVO.getEndTime() != null) { endTimeDate = DateUtils.parseDate(orderVO.getEndTime()); } else { endTimeDate = new Date(); } // 计算出两个时间差 chargingTime = DateUtils.getDatePoor(endTimeDate, startTimeDate); } orderVO.setChargingTime(chargingTime); } // 返回结果集 PageResponse pageResponse = PageResponse.builder() .pageNum(dto.getPageNum()) .pageSize(dto.getPageSize()) .list(pageInfo.getList()) .pages(pageInfo.getPages()) .total(pageInfo.getTotal()) .build(); return pageResponse; } /** * 微信支付v3 * * @param dto * @return * @throws Exception */ public Map weixinPayV3(WeixinPayDTO dto) throws Exception { return wechatPayService.weixinPayV3(dto); } /** * 用户停止充电 * * @param dto */ public void stopCharging(StopChargingDTO dto) { // 查订单 OrderBasicInfo orderInfo = orderBasicInfoService.getOrderInfoByOrderCode(dto.getOrderCode()); if (orderInfo == null) { throw new BusinessException(ReturnCodeEnum.CODE_QUERY_ORDER_INFO_IS_NULL); } // 判断订单状态是不是已经结算了 if (StringUtils.equals(orderInfo.getOrderStatus(), OrderStatusEnum.ORDER_COMPLETE.getValue())) { throw new BusinessException(ReturnCodeEnum.CODE_ORDER_COMPLETE_ERROR); } // 校验订单中的会员与操作会员是否一致 if (!StringUtils.equals(orderInfo.getMemberId(), dto.getMemberId())) { throw new BusinessException(ReturnCodeEnum.CODE_ORDER_MEMBER_NOT_MATCH_ERROR); } // 发送停止指令 pileRemoteService.remoteStopCharging(orderInfo.getPileSn(), orderInfo.getConnectorCode()); log.info("订单号:{}发送停机指令成功", dto.getOrderCode()); } /** * 微信退款 * * @param dto */ public void weChatRefund(ApplyRefundDTO dto) { log.info("微信退款接口 param:{}", JSONObject.toJSONString(dto)); orderBasicInfoService.weChatRefund(dto); } /** * 汇付退款 * * @param dto */ public void adapayRefund(ApplyRefundDTO dto) { log.info("汇付退款 param:{}", JSON.toJSONString(dto)); // 退款有两种情况 1-订单结算退款 2-用户余额退款 String refundType = dto.getRefundType(); if (StringUtils.equals(refundType, "1")) { orderBasicInfoService.refundOrderWithAdapay(dto); } else if (StringUtils.equals(refundType, "2")) { orderBasicInfoService.refundBalanceWithAdapay(dto); } else { log.warn("没有找到退款处理逻辑"); } } /** * 查询订单详情信息 * * @param orderCode 订单编号 * @return */ public OrderDetailInfoVO queryOrderDetailInfo(String orderCode) { OrderDetailInfoVO vo = new OrderDetailInfoVO(); // 订单信息 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(orderCode); if (orderBasicInfo == null) { return vo; } OrderDetailInfoVO.OrderInfo order = new OrderDetailInfoVO.OrderInfo(); order.setOrderCode(orderBasicInfo.getOrderCode()); order.setTransactionCode(orderBasicInfo.getTransactionCode()); order.setOrderStatus(orderBasicInfo.getOrderStatus()); order.setLogicCard(orderBasicInfo.getLogicCard()); String describe = orderBasicInfoService.transformOrderStatusDescribe(orderBasicInfo.getOrderStatus(), orderBasicInfo.getPayStatus()); order.setOrderStatusDescribe(describe); order.setStartTime(DateUtils.formatDateTime(orderBasicInfo.getChargeStartTime())); order.setEndTime(DateUtils.formatDateTime(orderBasicInfo.getChargeEndTime())); order.setCreateTime(DateUtils.formatDateTime(orderBasicInfo.getCreateTime())); order.setStopReasonMsg(orderBasicInfo.getReason()); order.setStartSOC(orderBasicInfo.getStartSOC()); order.setEndSOC(orderBasicInfo.getEndSOC()); order.setSettleAmount(String.valueOf(orderBasicInfo.getSettleAmount())); order.setSettlementTime(DateUtils.formatDateTime(orderBasicInfo.getSettlementTime())); vo.setOrderInfo(order); // 设备信息 PileInfoVO pileInfoVO = pileService.selectPileInfoBySn(orderBasicInfo.getPileSn()); vo.setPileInfo(pileInfoVO); // 枪口实时数据信息 String pileConnectorCode = orderBasicInfo.getPileSn() + orderBasicInfo.getConnectorCode(); QueryConnectorListDTO dto = new QueryConnectorListDTO(); dto.setConnectorCodeList(Lists.newArrayList(pileConnectorCode)); List chargingRealTimeDataList = orderBasicInfoService.getChargingRealTimeData(orderBasicInfo.getTransactionCode()); if (CollectionUtils.isNotEmpty(chargingRealTimeDataList)) { List infoList = Lists.newArrayList(); for (RealTimeMonitorData realTimeMonitorData : chargingRealTimeDataList) { OrderDetailInfoVO.PileMonitorData info = new OrderDetailInfoVO.PileMonitorData(); info.setInstantCurrent(realTimeMonitorData.getOutputCurrent()); // 电流 info.setInstantVoltage(realTimeMonitorData.getOutputVoltage()); // 电压 info.setInstantPower(realTimeMonitorData.getOutputPower()); // 功率 info.setSOC(realTimeMonitorData.getSOC()); info.setTime(realTimeMonitorData.getDateTime()); // 时间 infoList.add(info); } // 监控信息 OrderDetailInfoVO.OrderRealTimeInfo realTimeInfo = new OrderDetailInfoVO.OrderRealTimeInfo(); RealTimeMonitorData realTimeMonitorData = chargingRealTimeDataList.get(0); realTimeInfo.setOrderAmount(realTimeMonitorData.getChargingAmount()); realTimeInfo.setChargedDegree(realTimeMonitorData.getChargingDegree()); realTimeInfo.setChargingTime(realTimeMonitorData.getSumChargingTime()); realTimeInfo.setTime(realTimeMonitorData.getDateTime()); vo.setOrderRealTimeInfo(realTimeInfo); // 根据时间进行正序排序 infoList = infoList.stream() .sorted(Comparator.comparing(OrderDetailInfoVO.PileMonitorData::getTime)) .collect(Collectors.toList()); vo.setRealTimeMonitorDataList(infoList); // 最后一次实时数据 vo.setLastMonitorData(chargingRealTimeDataList.get(0)); } // 支付流水 List payRecords = orderPayRecordService.selectOrderPayInfoList(orderCode); vo.setPayRecordList(payRecords); // 查询退款明细 List orderRefundInfoList = getOrderRefundInfoList(orderBasicInfo); vo.setOrderRefundInfoList(orderRefundInfoList); // 查订单明细 OrderDetail orderDetail = orderBasicInfoService.getOrderDetailByOrderCode(orderCode); if (orderDetail != null) { OrderAmountDetailVO billingDetails = new OrderAmountDetailVO(); BeanUtils.copyBeanProp(billingDetails, orderDetail); vo.setBillingDetails(billingDetails); List orderPeriodAmountVOS = orderBasicInfoService.transformPeriodAmountByOrderDetail(orderDetail); vo.setChargeDetails(orderPeriodAmountVOS); } // 用户信息 MemberVO memberVO = memberService.getMemberInfoByMemberId(orderBasicInfo.getMemberId()); vo.setMemberInfo(memberVO); try { // 因为原来的数据在redis中是永久保存,所以这里做下查询详情的时候,发现已经是完成的订单,redis数据存到表中 if (StringUtils.equals(orderBasicInfo.getOrderStatus(), OrderStatusEnum.ORDER_COMPLETE.getValue())) { // 如果是已完成的订单,把redis中的实时数据存到表中 orderBasicInfoService.realTimeMonitorDataRedis2DB(orderBasicInfo.getTransactionCode(), orderBasicInfo.getOrderCode()); } } catch (Exception e) { log.error("后管查询订单详情时把redis中的实时数据存到表发生异常", e); } return vo; } /** * 获取退款明细列表 * @param orderBasicInfo * @return */ private List getOrderRefundInfoList(OrderBasicInfo orderBasicInfo) { List orderRefundInfoList = Lists.newArrayList(); if (OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue().equals(orderBasicInfo.getPayMode())) { // 查新member_wallet_log订单退款记录 // memberWalletLogService. } else if (OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue().equals(orderBasicInfo.getPayMode())) { List paymentReverseResponses = orderBasicInfoService.queryOrderAdapayRefund(orderBasicInfo); if (CollectionUtils.isNotEmpty(paymentReverseResponses)) { OrderDetailInfoVO.OrderRefundInfo refundInfo; for (PaymentReverseResponse reverseResponse : paymentReverseResponses) { refundInfo = new OrderDetailInfoVO.OrderRefundInfo(); refundInfo.setReverseId(reverseResponse.getId()); refundInfo.setPaymentId(reverseResponse.getPayment_id()); refundInfo.setReverseAmt(reverseResponse.getReverse_amt()); LocalDateTime createdTime = DateUtils.timestampToDatetime(Long.parseLong(reverseResponse.getCreated_time())); refundInfo.setCreatedTime(DateUtils.formatDateTime(createdTime)); LocalDateTime succeedTime = DateUtils.timestampToDatetime(Long.parseLong(reverseResponse.getSucceed_time())); refundInfo.setSucceedTime(DateUtils.formatDateTime(succeedTime)); orderRefundInfoList.add(refundInfo); } } } return orderRefundInfoList; } /** * 微信支付退款回调 * * @param request * @param body * @throws Exception */ public void wechatPayRefundCallback(HttpServletRequest request, WechatPayNotifyParameter body) throws Exception { // 获取微信退款成功返回的信息 Map map = wechatPayService.wechatPayRefundCallbackInfo(request, body); } /** * 获取小程序订单详情 * * @param orderCode * @return */ public UniAppOrderVO getUniAppOrderDetail(String orderCode) { OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(orderCode); if (orderBasicInfo == null) { throw new BusinessException(ReturnCodeEnum.CODE_QUERY_ORDER_INFO_IS_NULL); } UniAppOrderVO vo = new UniAppOrderVO(); vo.setOrderCode(orderBasicInfo.getOrderCode()); vo.setPileSn(orderBasicInfo.getPileSn()); vo.setConnectorCode(orderBasicInfo.getConnectorCode()); vo.setPileConnectorCode(orderBasicInfo.getPileSn() + orderBasicInfo.getConnectorCode()); String orderStatus = orderBasicInfo.getOrderStatus(); vo.setOrderStatus(orderStatus); if (Objects.nonNull(orderBasicInfo.getChargeStartTime())) { vo.setStartChargingTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, orderBasicInfo.getChargeStartTime())); } Date chargeEndTime = orderBasicInfo.getChargeEndTime(); if (Objects.nonNull(chargeEndTime)) { vo.setEndChargingTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, chargeEndTime)); } PileStationVO stationInfo = pileStationInfoService.getStationInfo(orderBasicInfo.getStationId()); vo.setStationName(stationInfo.getStationName()); vo.setReason(orderBasicInfo.getReason()); vo.setOrderAmount(String.valueOf(orderBasicInfo.getOrderAmount())); vo.setPayAmount(String.valueOf(orderBasicInfo.getPayAmount())); vo.setPayMode(orderBasicInfo.getPayMode()); // 订单状态描述 String orderStatusDescribe = orderBasicInfoService.transformOrderStatusDescribe(orderStatus, orderBasicInfo.getPayStatus()); vo.setOrderStatusDescribe(orderStatusDescribe); // 获取充电桩枪口信息 PileConnectorDetailVO pileConnectorDetailVO = pileService.queryPileConnectorDetail(vo.getPileConnectorCode()); if (pileConnectorDetailVO != null) { vo.setPileConnectorStatus(pileConnectorDetailVO.getConnectorStatus()); } // 获取订单充电数据 List monitorDataList = orderBasicInfoService.getChargingRealTimeData(orderBasicInfo.getTransactionCode()); if (CollectionUtils.isNotEmpty(monitorDataList)) { List chargingDataList = Lists.newArrayList(); UniAppOrderVO.ChargingData data = null; for (int i = 0; i < monitorDataList.size(); i++) { RealTimeMonitorData monitorData = monitorDataList.get(i); data = new UniAppOrderVO.ChargingData(); data.setDateTime(monitorData.getDateTime()); String outputVoltage = monitorData.getOutputVoltage(); data.setOutputVoltage(outputVoltage); String outputCurrent = monitorData.getOutputCurrent(); data.setOutputCurrent(outputCurrent); BigDecimal power = new BigDecimal(outputCurrent).multiply(new BigDecimal(outputVoltage)) .divide(new BigDecimal("1000"), 2, BigDecimal.ROUND_HALF_UP); data.setPower(power.toString()); data.setSOC(monitorData.getSOC()); data.setBatteryMaxTemperature(monitorData.getBatteryMaxTemperature()); chargingDataList.add(data); // vo中的实时数据,最新一条就取monitorDataList第一个 if (i == 0) { vo.setBatteryMaxTemperature(data.getBatteryMaxTemperature()); vo.setOutputPower(data.getPower()); vo.setOutputCurrent(data.getOutputCurrent()); vo.setOutputVoltage(data.getOutputVoltage()); vo.setSOC(data.getSOC()); BigDecimal chargingAmount = new BigDecimal(monitorData.getChargingAmount()).setScale(2, BigDecimal.ROUND_HALF_UP); // 充电金额 vo.setChargingAmount(chargingAmount.toString()); BigDecimal chargingDegree = new BigDecimal(monitorData.getChargingDegree()).setScale(2, BigDecimal.ROUND_HALF_UP); // 充电度数 vo.setChargingDegree(chargingDegree.toString()); vo.setSumChargingTime(monitorData.getSumChargingTime()); vo.setTimeRemaining(monitorData.getTimeRemaining()); } } // monitorDataList是按照时间倒序的,chargingDataList需要按照时间正序 Collections.reverse(chargingDataList); vo.setChargingDataList(chargingDataList); } OrderDetail orderDetail = orderBasicInfoService.getOrderDetailByOrderCode(orderCode); if (orderDetail != null) { OrderAmountDetailVO billingDetails = new OrderAmountDetailVO(); BeanUtils.copyBeanProp(billingDetails, orderDetail); vo.setBillingDetails(billingDetails); } try { // 因为原来的数据在redis中是永久保存,所以这里做下查询详情的时候,发现已经是完成的订单,redis数据存到表中 if (StringUtils.equals(orderBasicInfo.getOrderStatus(), OrderStatusEnum.ORDER_COMPLETE.getValue())) { // 如果是已完成的订单,把redis中的实时数据存到表中 orderBasicInfoService.realTimeMonitorDataRedis2DB(orderBasicInfo.getTransactionCode(), orderBasicInfo.getOrderCode()); } } catch (Exception e) { log.error("后管查询订单详情时把redis中的实时数据存到表发生异常", e); } return vo; } /** * 小程序订单详情V2 * * @param orderCode * @return */ public UniAppOrderDetailVO getUniAppOrderDetailV2(String orderCode) { UniAppOrderDetailVO resultVO = new UniAppOrderDetailVO(); return resultVO; } /** * 根据订单号查询充电桩启动状态 * * @param orderCode * @return */ public String selectPileStarterStatus(String orderCode) { OrderBasicInfo orderInfoByOrderCode = orderBasicInfoService.getOrderInfoByOrderCode(orderCode); if (orderInfoByOrderCode == null) { return Constants.ZERO; } List chargingRealTimeData = orderBasicInfoService.getChargingRealTimeData(orderInfoByOrderCode.getTransactionCode()); // 只有充电桩上传的实时数据中的状态为充电,才能查到实时数据列表 return CollectionUtils.isNotEmpty(chargingRealTimeData) ? Constants.ONE : Constants.ZERO; } /** * 关闭支付未启动的订单 * * @param dto */ public void closeStartFailedOrder(QueryOrderDTO dto) { orderBasicInfoService.closeStartFailedOrder(dto.getStartTime(), dto.getEndTime()); } /** * 人工结算订单 * * @param dto */ public boolean manualSettlementOrder(ManualSettlementDTO dto) { log.info("人工结算订单-begin orderCode:{}", dto.getOrderCode()); // 查询订单 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(dto.getOrderCode()); if (orderBasicInfo == null) { log.info("人工结算订单-根据订单号:{}, 查询为null", dto.getOrderCode()); return false; } // 当前登录用户,是否可以结算该订单 AuthorizedDeptVO authorizedMap = SecurityUtils.getAuthorizedMap(); if (authorizedMap == null) { log.info("人工结算订单-当前登录管理员无权限"); return false; } List stationDeptIds = authorizedMap.getStationDeptIds(); if (CollectionUtils.isEmpty(stationDeptIds)) { // 运营商管理员 List merchantDeptIds = authorizedMap.getMerchantDeptIds(); } String chargingAmount = dto.getChargingAmount(); String chargingDegree = dto.getChargingDegree(); if (StringUtils.equals(chargingAmount, Constants.ZERO) || StringUtils.equals(chargingDegree, Constants.ZERO)) { // 获取最后一次实时数据 List chargingRealTimeData = orderBasicInfoService.getChargingRealTimeData(orderBasicInfo.getTransactionCode()); if (CollectionUtils.isNotEmpty(chargingRealTimeData)) { RealTimeMonitorData realTimeMonitorData = chargingRealTimeData.get(0); chargingAmount = realTimeMonitorData.getChargingAmount(); chargingDegree = realTimeMonitorData.getChargingDegree(); } } // 组装交易记录数据 TransactionRecordsData data = new TransactionRecordsData(); data.setConsumptionAmount(chargingAmount); // 总消费金额 data.setTotalElectricity(chargingDegree); // 总用电量 data.setStopReasonMsg("人工结算订单,操作人:" + SecurityUtils.getUsername()); // 停止原因 // 结算订单 // orderBasicInfoService.settleOrder(data, orderBasicInfo); // 新逻辑 String mode = pileMerchantInfoService.getDelayModeByMerchantId(orderBasicInfo.getMerchantId()); AbstractOrderLogic orderLogic = OrderLogicFactory.getOrderLogic(mode); orderLogic.settleOrder(data, orderBasicInfo); // 发送停止充电指令 pileRemoteService.remoteStopCharging(orderBasicInfo.getPileSn(), orderBasicInfo.getConnectorCode()); log.info("人工结算订单-end orderCode:{}", dto.getOrderCode()); return true; } /** * 当前登录会员 获取支付方式 * * @param dto */ public List getPayMode(GetPayModeDTO dto) { List result = Lists.newArrayList(); // 查询会员在站点是否是白名单用户 PileStationWhitelist whitelist = pileStationWhitelistService.queryWhitelistByMemberId(dto.getStationId(), dto.getMemberId()); // 查询是否为平台测试员 PlatformTesterVO platformTesterVO = memberBasicInfoService.selectPlatformTesterStatus(dto.getMemberId()); boolean flag = whitelist != null || StringUtils.equals(platformTesterVO.getStatus(), Constants.ONE); if (flag) { result.add( PayModeVO.builder() .payModeCode(OrderPayModeEnum.PAYMENT_OF_WHITELIST.getValue()) .payModeName(OrderPayModeEnum.PAYMENT_OF_WHITELIST.getLabel()) .build() ); } else { // 微信支付 result.add( PayModeVO.builder() .payModeCode(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue()) .payModeName(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getLabel()) .build() ); // 余额支付 result.add( PayModeVO.builder() .payModeCode(OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue()) .payModeName(OrderPayModeEnum.PAYMENT_OF_BALANCE.getLabel()) .build() ); } return result; } /** * 查询未开发票订单 * 时间限制15天内 * * @param dto * @return */ public List queryUninvoicedOrderList(QueryOrderDTO dto) { int i = 15; // 查询最近15天完成的订单 LocalDateTime dateTime = LocalDateTime.now().plusDays(-i); List orderList = orderBasicInfoService.getListByMemberIdAndOrderStatus(dto.getMemberId(), Lists.newArrayList("6"), dateTime); // 过滤掉订单金额为0的 orderList = orderList.stream() .filter(x -> x.getSettleAmount().compareTo(BigDecimal.ZERO) > 0) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(orderList)) { return orderList; } // 查询最近60天申请开票记录 QueryInvoiceRecordDTO build = QueryInvoiceRecordDTO.builder() .memberId(dto.getMemberId()) .startTime(dateTime) .build(); List orderInvoiceRecords = orderInvoiceRecordService.selectInvoiceRecordList(build); if (CollectionUtils.isEmpty(orderInvoiceRecords)) { return orderList; } // 排除掉已经申请过的订单 List orderCodeList = orderInvoiceRecords.stream() // 转化为 Stream .map(OrderInvoiceRecord::getOrderCodes) // 获取 OrderInvoiceRecord 中的 orderCodes 字符串 .flatMap(str -> Arrays.stream(str.split(Constants.DEFAULT_DELIMITER))) // 分隔逗号并转化为 Stream .collect(Collectors.toList()); // 收集为 List orderList = orderList.stream() .filter(x -> !orderCodeList.contains(x.getOrderCode())) .collect(Collectors.toList()); return orderList; } public List queryUninvoicedStationList(QueryOrderDTO dto) { return Lists.newArrayList(); } /** * 申请开票 * * @param dto */ public void applyOrderInvoice(ApplyOrderInvoiceDTO dto) { int i = 15; // 查询最近15天完成的订单 LocalDateTime dateTime = LocalDateTime.now().plusDays(-i); // 查询最近15天 会员的开票记录 List orderInvoiceRecords = orderInvoiceRecordService.selectInvoiceRecordList(dto.getMemberId(), dateTime, LocalDateTime.now()); List orderCodeList = orderInvoiceRecords.stream() // 转化为 Stream .map(OrderInvoiceRecord::getOrderCodes) // 获取 OrderInvoiceRecord 中的 orderCodes 字符串 .flatMap(str -> Arrays.stream(str.split(Constants.DEFAULT_DELIMITER))) // 分隔逗号并转化为 Stream .collect(Collectors.toList()); // 收集为 List // 取交集 校验订单是否已经开票 Set intersection = Sets.intersection(Sets.newHashSet(orderCodeList), Sets.newHashSet(dto.getOrderCodes())); if (CollectionUtils.isNotEmpty(intersection)) { log.info("申请开票前端传的:{}订单号list, 包含已经申请的订单:{}", dto.getOrderCodes(), intersection); return; } // 查抬头信息 MemberInvoiceTitle invoiceTitle = memberInvoiceTitleService.selectMemberInvoiceTitleById(Long.parseLong(dto.getTitleId())); if (StringUtils.isNotEmpty(dto.getReception())) { boolean b = false; if (StringUtils.isEmail(dto.getReception()) && !StringUtils.equals(dto.getReception(), invoiceTitle.getEmail())) { invoiceTitle.setEmail(dto.getReception()); b = true; } if (StringUtils.isPhoneNumber(dto.getReception()) && !StringUtils.equals(dto.getReception(), invoiceTitle.getPhoneNumber())) { invoiceTitle.setPhoneNumber(dto.getReception()); b = true; } if (b) { memberInvoiceTitleService.updateMemberInvoiceTitle(invoiceTitle); } } // 整理数据 List orderVOList = orderBasicInfoService.getListByOrderCodes(dto.getOrderCodes()); // 根据运营商分组 Map> map = orderVOList.stream().collect(Collectors.groupingBy(OrderVO::getMerchantId)); BigDecimal totalAmount = null; BigDecimal totalElecAmount = null; BigDecimal totalServiceAmount = null; // 根据运营商创建多笔开票记录 for (Map.Entry> entry : map.entrySet()) { totalAmount = BigDecimal.ZERO; totalElecAmount = BigDecimal.ZERO; totalServiceAmount = BigDecimal.ZERO; List orders = entry.getValue(); for (OrderVO orderVO : orders) { totalAmount = totalAmount.add(orderVO.getOrderAmount()); totalElecAmount = totalElecAmount.add(orderVO.getTotalElectricityAmount()); totalServiceAmount = totalServiceAmount.add(orderVO.getTotalServiceAmount()); } // 入库 OrderInvoiceRecord orderInvoiceRecord = new OrderInvoiceRecord(); orderInvoiceRecord.setStatus(Constants.ZERO); orderInvoiceRecord.setMemberId(dto.getMemberId()); orderInvoiceRecord.setMerchantId(entry.getKey()); orderInvoiceRecord.setTitleId(dto.getTitleId()); orderInvoiceRecord.setOrderCodes(String.join(Constants.DEFAULT_DELIMITER, dto.getOrderCodes())); orderInvoiceRecord.setTotalAmount(totalAmount); orderInvoiceRecord.setTotalElecAmount(totalElecAmount); orderInvoiceRecord.setTotalServiceAmount(totalServiceAmount); orderInvoiceRecordService.insertOrderInvoiceRecord(orderInvoiceRecord); } } /** * 查询开票记录 * * @param dto * @return */ public PageResponse queryInvoiceRecord(QueryInvoiceRecordDTO dto) { QueryInvoiceRecordDTO build = QueryInvoiceRecordDTO.builder() .memberId(dto.getMemberId()) .build(); int pageNo = dto.getPageNo() == null ? 1 : dto.getPageNo(); int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize(); PageHelper.startPage(pageNo, pageSize); List orderInvoiceRecords = orderInvoiceRecordService.selectInvoiceRecordList(build); PageInfo pageInfo = new PageInfo<>(orderInvoiceRecords); List volist = Lists.newArrayList(); for (OrderInvoiceRecord orderInvoiceRecord : orderInvoiceRecords) { volist.add( InvoiceRecordVO.builder() .status(InvoiceRecordEnum.getLabel(orderInvoiceRecord.getStatus())) .totalAmount(orderInvoiceRecord.getTotalAmount()) .totalElecAmount(orderInvoiceRecord.getTotalElecAmount()) .totalServiceAmount(orderInvoiceRecord.getTotalServiceAmount()) .createTime(DateUtils.formatDateTime(orderInvoiceRecord.getCreateTime())) .build() ); } return PageResponse.builder() .total(pageInfo.getTotal()) .pages(pageInfo.getPages()) .pageNum(pageInfo.getPageNum()) .pageSize(pageInfo.getPageSize()) .list(volist) .build(); } /** * 汇付支付 支付回调 * * @param request * @throws Exception */ public void adapayCallback(HttpServletRequest request) throws Exception { // 验签请参data String data = request.getParameter("data"); // 验签请参sign String sign = request.getParameter("sign"); // 验签请参publicKey String publicKey = AdapayCore.PUBLIC_KEY; log.info("汇付支付回调验签请参data={}, sign={}", data, sign); // 验签标记 boolean checkSign = AdapaySign.verifySign(data, sign, publicKey); if (!checkSign) { log.info("汇付支付回调验签失败:{}", data); return; } // type String type = request.getParameter("type"); // 根据type执行不同逻辑 if (AdapayEventEnum.payment_succeeded.getValue().equals(type)) { // 支付成功 paymentSucceeded(data); } else if (AdapayEventEnum.refund_succeeded.getValue().equals(type)) { // 退款成功 refundSucceeded(data); } else if (AdapayEventEnum.refund_failed.getValue().equals(type)) { // 退款失败 refundFailed(data); } else if (AdapayEventEnum.corp_member_failed.getValue().equals(type)) { // 开户失败 删除 corpMemberFailed(data); } else if (AdapayEventEnum.corp_member_succeeded.getValue().equals(type)) { // 开户成功 corpMemberSucceeded(data); } else if (AdapayEventEnum.payment_reverse_succeeded.getValue().equals(type)) { // 支付撤销成功 paymentReverseSucceeded(data); } else if (AdapayEventEnum.payment_reverse_failed.getValue().equals(type)) { // 支付撤销失败 paymentReverseFailed(data); } else if (AdapayEventEnum.cash_succeeded.getValue().equals(type)) { // 取现成功 cashSucceeded(data); } else if (AdapayEventEnum.cash_failed.getValue().equals(type)) { // 取现失败 cashFailed(data); } } /** * adapay支付成功回调 * * @param data * @throws JsonProcessingException */ private void paymentSucceeded(String data) throws JsonProcessingException { // 验签成功 保存到回调记录表中 JSONObject jsonObject = JSON.parseObject(data); ObjectMapper mapper = new ObjectMapper(); mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); AdapayCallbackRecord adapayCallbackRecord = mapper.readValue(jsonObject.toJSONString(), AdapayCallbackRecord.class); // 支付扩展域 adapayCallbackRecord.setExpend(jsonObject.getString("expend")); // 支付id String paymentId = jsonObject.getString("id"); adapayCallbackRecord.setPaymentId(paymentId); // 订单附加说明 JSONObject descJson = JSON.parseObject(adapayCallbackRecord.getDescription()); // 支付回调中包含的场景类型 String scenarioType = descJson.getString("type"); adapayCallbackRecord.setPayScenario(scenarioType); // 支付回调中包含的会员id String memberId = descJson.getString("memberId"); adapayCallbackRecord.setMemberId(memberId); // 支付回调中包含的订单编号 String orderCode = descJson.getString("orderCode"); adapayCallbackRecord.setOrderCode(orderCode); // 支付金额 BigDecimal amount = adapayCallbackRecord.getPayAmt(); // 保存到数据库 adapayCallbackRecordService.saveAdapayCallbackRecord(adapayCallbackRecord); // 保存MemberAdapayRecord MemberAdapayRecord memberAdapayRecord = new MemberAdapayRecord(); memberAdapayRecord.setMemberId(memberId); memberAdapayRecord.setPaymentId(paymentId); memberAdapayRecord.setPaymentOrderNo(adapayCallbackRecord.getOutTransId()); memberAdapayRecord.setScenarioType(scenarioType); memberAdapayRecord.setPayAmt(amount); memberAdapayRecord.setRefundAmt(BigDecimal.ZERO); memberAdapayRecord.setSpendAmt(BigDecimal.ZERO); memberAdapayRecord.setFreezeAmt(BigDecimal.ZERO); memberAdapayRecord.setBalanceAmt(amount); memberAdapayRecordService.insertSelective(memberAdapayRecord); // 微信支付订单 记录会员交易流水 MemberTransactionRecord record = MemberTransactionRecord.builder() .orderCode(orderCode) .scenarioType(scenarioType) .memberId(memberId) .actionType(ActionTypeEnum.FORWARD.getValue()) .payMode(PayModeEnum.PAYMENT_OF_WECHATPAY.getValue()) .paymentInstitutions(PaymentInstitutionsEnum.ADAPAY.getValue()) .amount(amount) // 单位元 .outTradeNo(adapayCallbackRecord.getPartyOrderId()) .transactionId(adapayCallbackRecord.getOutTransId()) .build(); memberTransactionRecordService.insertSelective(record); if (StringUtils.equals(scenarioType, ScenarioEnum.ORDER.getValue())) { // 1-订单支付 JSONObject json = new JSONObject(); json.put("paymentId", paymentId); json.put("amount", amount); // 记录订单支付流水 OrderPayRecord orderPayRecord = OrderPayRecord.builder() .orderCode(orderCode) .payMode(OrderPayRecordEnum.WECHATPAY_PAYMENT.getValue()) .payAmount(amount) .acquirer(AcquirerEnum.ADAPAY.getValue()) .deductionRecord(json.toJSONString()) .createBy(null) .delFlag(DelFlagEnum.NORMAL.getValue()) .build(); orderPayRecordService.batchInsert(Lists.newArrayList(orderPayRecord)); // 更新冻结金额 支付成功后全部冻结 memberAdapayRecordService.updateFreezeAmount(paymentId, amount); // 支付订单成功 PayOrderSuccessCallbackDTO callbackDTO = PayOrderSuccessCallbackDTO.builder() .orderCode(orderCode) .payAmount(amount) .payMode(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue()) .acquirer(AcquirerEnum.ADAPAY.getValue()) .build(); // 订单支付成功 支付回调 orderBasicInfoService.payOrderSuccessCallback(callbackDTO); } else if (StringUtils.equals(scenarioType, ScenarioEnum.BALANCE.getValue())) { // 2-充值余额 // 充值余额成功 UpdateMemberBalanceDTO dto = new UpdateMemberBalanceDTO(); dto.setMemberId(memberId); dto.setType(MemberWalletEnum.TYPE_IN.getValue()); dto.setSubType(MemberWalletEnum.SUBTYPE_TOP_UP.getValue()); dto.setUpdatePrincipalBalance(amount); memberBasicInfoService.updateMemberBalance(dto); } else if (StringUtils.equals(scenarioType, ScenarioEnum.OCCUPY.getValue())) { // 占桩订单 // 通过订单号查询出占桩订单信息 OrderPileOccupy orderPileOccupy = orderPileOccupyService.queryByOccupyCode(orderCode); // 订单状态改为 1-订单完成 orderPileOccupy.setStatus(OccupyOrderStatusEnum.ORDER_COMPLETE.getCode()); // 支付状态改为 1-支付完成 orderPileOccupy.setPayStatus(OccupyOrderPayStatusEnum.PAYMENT_COMPLETION.getCode()); orderPileOccupyService.updateByPrimaryKey(orderPileOccupy); } } /** * 汇付退款成功 */ private void refundSucceeded(String data) { log.info("退款成功 data:{}", JSON.toJSONString(data)); // 保存退款回调记录 adapayRefundRecordService.saveAdapayRefundRecord(data); JSONObject jsonObject = JSON.parseObject(data); JSONObject reason = jsonObject.getJSONObject("reason"); if (ScenarioEnum.BALANCE.getValue().equals(reason.getString("scenarioType"))) { // 这笔支付订单原来是充值余额的,退款成功了,需要扣掉会员的本金金额 UpdateMemberBalanceDTO dto = new UpdateMemberBalanceDTO(); String memberId = reason.getString("memberId"); dto.setMemberId(memberId); dto.setUpdatePrincipalBalance(new BigDecimal(jsonObject.getString("refund_amt"))); // 更新会员本金金额,单位元 dto.setType(MemberWalletEnum.TYPE_OUT.getValue()); dto.setSubType(MemberWalletEnum.SUBTYPE_USER_REFUND.getValue()); memberBasicInfoService.updateMemberBalance(dto); // 收到回调,删除缓存 String redisKey = CacheConstants.MEMBER_BALANCE_REFUNDS_ARE_IN_PROGRESS + memberId; redisCache.deleteObject(redisKey); } } /** * 退款失败 * * @param data */ private void refundFailed(String data) { log.info("退款失败 data:{}", JSON.toJSONString(data)); JSONObject jsonObject = JSON.parseObject(data); JSONObject reason = jsonObject.getJSONObject("reason"); if (ScenarioEnum.BALANCE.getValue().equals(reason.getString("scenarioType"))) { String memberId = reason.getString("memberId"); // 收到回调,删除缓存 String redisKey = CacheConstants.MEMBER_BALANCE_REFUNDS_ARE_IN_PROGRESS + memberId; redisCache.deleteObject(redisKey); } } /** * 对公账户创建失败 */ private void corpMemberFailed(String data) { // 删除表中的记录 JSONObject jsonObject = JSON.parseObject(data); String memberId = jsonObject.getString("member_id"); if (StringUtils.isBlank(memberId)) { return; } AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMemberId(memberId); if (adapayMemberAccount == null) { return; } adapayMemberAccount.setStatus(Constants.TWO); // 逻辑删除记录,并删除缓存 adapayMemberAccountService.updateAdapayMemberAccount(adapayMemberAccount); } /** * 对公账户创建成功 */ private void corpMemberSucceeded(String data) { JSONObject jsonObject = JSON.parseObject(data); String memberId = jsonObject.getString("member_id"); if (StringUtils.isBlank(memberId)) { return; } AdapayMemberAccount adapayMemberAccount = new AdapayMemberAccount(); adapayMemberAccount.setAdapayMemberId(memberId); adapayMemberAccount.setStatus(Constants.ONE); adapayMemberAccountService.updateAdapayMemberAccountByMemberId(adapayMemberAccount); } /** * 取现成功 */ private void cashSucceeded(String data) { JSONObject jsonObject = JSON.parseObject(data); String withdrawCode = jsonObject.getString("id"); // 通过取现id查询取现数据 ClearingWithdrawInfo clearingWithdrawInfo = clearingWithdrawInfoService.selectByWithdrawCode(withdrawCode); clearingWithdrawInfo.setWithdrawStatus(Constants.ONE); clearingWithdrawInfo.setUpdateTime(DateUtils.getNowDate()); clearingWithdrawInfoService.updateByPrimaryKeySelective(clearingWithdrawInfo); } /** * 取现失败 * * @param data */ private void cashFailed(String data) { JSONObject jsonObject = JSON.parseObject(data); String withdrawCode = jsonObject.getString("id"); // 通过取现id查询取现数据 ClearingWithdrawInfo clearingWithdrawInfo = clearingWithdrawInfoService.selectByWithdrawCode(withdrawCode); clearingWithdrawInfo.setWithdrawStatus(Constants.TWO); clearingWithdrawInfo.setUpdateTime(DateUtils.getNowDate()); clearingWithdrawInfoService.updateByPrimaryKeySelective(clearingWithdrawInfo); } /** * 支付撤销成功 */ private void paymentReverseSucceeded(String data) { log.info("支付撤销成功 data:{}", JSON.toJSONString(data)); JSONObject jsonObject = JSON.parseObject(data); JSONObject reason = jsonObject.getJSONObject("reason"); if (ScenarioEnum.BALANCE.getValue().equals(reason.getString("scenarioType"))) { // 这笔支付订单原来是充值余额的,退款成功了,需要扣掉会员的本金金额 UpdateMemberBalanceDTO dto = new UpdateMemberBalanceDTO(); String memberId = reason.getString("memberId"); dto.setMemberId(memberId); dto.setUpdatePrincipalBalance(new BigDecimal(jsonObject.getString("reverse_amt"))); // 更新会员本金金额,单位元 dto.setType(MemberWalletEnum.TYPE_OUT.getValue()); dto.setSubType(MemberWalletEnum.SUBTYPE_USER_REFUND.getValue()); memberBasicInfoService.updateMemberBalance(dto); // 收到回调,删除缓存 String redisKey = CacheConstants.MEMBER_BALANCE_REFUNDS_ARE_IN_PROGRESS + memberId; redisCache.deleteObject(redisKey); } } /** * 支付撤销失败 */ private void paymentReverseFailed(String data) { log.info("支付撤销失败 data:{}", JSON.toJSONString(data)); JSONObject jsonObject = JSON.parseObject(data); JSONObject reason = jsonObject.getJSONObject("reason"); if (ScenarioEnum.BALANCE.getValue().equals(reason.getString("scenarioType"))) { String memberId = reason.getString("memberId"); // 收到回调,删除缓存 String redisKey = CacheConstants.MEMBER_BALANCE_REFUNDS_ARE_IN_PROGRESS + memberId; redisCache.deleteObject(redisKey); } } public Map payOccupyPileOrder(PayOrderDTO dto) { return orderPileOccupyService.payOccupyPileOrder(dto); } }