Files
jsowell-charger-web/jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java
YAS\29473 5694a027d5 update
2025-07-10 10:05:37 +08:00

479 lines
20 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.jsowell.quartz.task;
import com.google.common.collect.Lists;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.jsowell.adapay.common.DivMember;
import com.jsowell.adapay.dto.PaymentConfirmParam;
import com.jsowell.adapay.dto.WithdrawDTO;
import com.jsowell.adapay.response.PaymentConfirmResponse;
import com.jsowell.adapay.service.AdapayService;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.adapay.AdapayStatusEnum;
import com.jsowell.common.enums.thirdparty.ThirdPlatformTypeEnum;
import com.jsowell.common.util.AdapayUtil;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.PageUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.spring.SpringUtils;
import com.jsowell.pile.domain.OrderBasicInfo;
import com.jsowell.pile.domain.OrderUnsplitRecord;
import com.jsowell.pile.domain.PileMerchantInfo;
import com.jsowell.pile.domain.PileStationInfo;
import com.jsowell.pile.domain.ykcCommond.PublishPileBillingTemplateCommand;
import com.jsowell.pile.domain.ykcCommond.StartChargingCommand;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.base.StationInfoVO;
import com.jsowell.pile.vo.web.BillingTemplateVO;
import com.jsowell.thirdparty.amap.service.AMapService;
import com.jsowell.thirdparty.platform.service.impl.GuiZhouPlatformServiceImpl;
import com.jsowell.thirdparty.platform.service.impl.SiChuanPlatformServiceImpl;
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.Component;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Component("jsowellTask")
public class JsowellTask {
private final Logger log = LoggerFactory.getLogger(JsowellTask.class);
@Autowired
private OrderBasicInfoService orderBasicInfoService;
@Autowired
private PileBillingTemplateService pileBillingTemplateService;
@Autowired
private YKCPushCommandService ykcPushCommandService;
@Autowired
private PileMerchantInfoService pileMerchantInfoService;
@Autowired
private PileStationInfoService pileStationInfoService;
@Autowired
private RedisCache redisCache;
@Autowired
private AMapService aMapService;
@Autowired
private AdapayService adapayService;
@Autowired
private SettleOrderReportService settleOrderReportService;
@Autowired
private ThirdPartyStationRelationService thirdPartyStationRelationService;
@Autowired
private OrderUnsplitRecordService orderUnsplitRecordService;
/**
* 设置挡板, PRE环境不执行
*/
public void setBarrier() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
}
/**
* 关闭15分钟未支付的订单
* close15MinutesOfUnpaidOrders
*/
public void close15MinutesOfUnpaidOrders() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// log.info("关闭15分钟未支付的订单");
orderBasicInfoService.close15MinutesOfUnpaidOrders();
}
/**
* 关闭启动失败的订单
* 订单支付成功在15分钟内未启动
*/
public void closeStartFailedOrder() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询出最近2天支付成功并且订单状态为未启动的订单
String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addDays(new Date(), -2));
String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date());
orderBasicInfoService.closeStartFailedOrder(startTime, endTime);
}
/**
* 查询预约充电的订单并启动
*/
public void appointmentOrderStart() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询出 已支付 设置预约充电 未启动 的订单
LocalDateTime now = LocalDateTime.now();
List<OrderBasicInfo> list = orderBasicInfoService.getReservedOrder(now);
if (CollectionUtils.isEmpty(list)) {
return;
}
log.info("待启动充电订单:{}", list);
for (OrderBasicInfo orderInfo : list) {
// 下发充电桩设置指令
String pileSn = orderInfo.getPileSn();
// 发送启动充电指令前,再次下发计费模板
BillingTemplateVO billingTemplateVO = pileBillingTemplateService.selectBillingTemplateDetailByPileSn(pileSn);
if (billingTemplateVO != null) {
PublishPileBillingTemplateCommand command = PublishPileBillingTemplateCommand.builder()
.billingTemplateVO(billingTemplateVO)
.pileSn(pileSn)
.build();
ykcPushCommandService.pushPublishPileBillingTemplate(command);
}
// 发送启动指令
String connectorCode = orderInfo.getConnectorCode();
String transactionCode = orderInfo.getTransactionCode();
BigDecimal payAmount = orderInfo.getPayAmount();
if (StringUtils.isEmpty(pileSn) || StringUtils.isEmpty(connectorCode)) {
log.warn("appointmentOrderStart-远程启动充电, 充电桩编号和枪口号不能为空");
return;
}
log.info("appointmentOrderStart 远程启动充电, 桩号:{}, 枪口号:{}", pileSn, connectorCode);
StartChargingCommand startChargingCommand = StartChargingCommand.builder()
.pileSn(pileSn)
.connectorCode(connectorCode)
.transactionCode(transactionCode)
.chargeAmount(payAmount)
.build();
ykcPushCommandService.pushStartChargingCommand(startChargingCommand);
}
}
/**
* 计算站点订单报表
* jsowellTask.calculateTheSiteOrdersReport()
*/
public void calculateTheSiteOrdersReport() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询出所有站点
PileStationInfo pileStationInfo = new PileStationInfo();
pileStationInfo.setDelFlag(Constants.ZERO);
// 查询未删除的站点列表
List<PileStationInfo> list = pileStationInfoService.selectPileStationInfoList(pileStationInfo);
if (CollectionUtils.isEmpty(list)) {
return;
}
LocalDate yesterday = LocalDate.now().plusDays(-1);
// 计算每个站点前一天的报表
for (PileStationInfo stationInfo : list) {
try {
settleOrderReportService.generateDailyOrderReports(stationInfo.getId() + "", yesterday.toString());
} catch (Exception e) {
log.error("计算站点订单报表 发生异常 stationId:{}", stationInfo.getId(), e);
}
}
}
/**
* 站点的枪口数据推送到高德
* jsowellTask.pushToAMap()
*/
public void pushToAMap() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
Set<String> stationIds = redisCache.getCacheSet(CacheConstants.PUSH_STATION_CONNECTOR);
if (CollectionUtils.isEmpty(stationIds)) {
return;
}
log.info("推送到高德的stationId:{}", stationIds);
for (String stationId : stationIds) {
try {
aMapService.pushChargingDeviceDynamics(stationId);
} catch (Exception e) {
log.error("推送到高德error", e);
}
}
// 删除缓存
redisCache.deleteObject(CacheConstants.PUSH_STATION_CONNECTOR);
}
/**
* 贵州省平台推送充电站实时功率 15分钟执行一次
*/
public void pushStationRealTimePowerInfo() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询出要推送的站点(贵州、)
String thirdPartyType = ThirdPlatformTypeEnum.GUI_ZHOU_PLATFORM.getTypeCode();
List<StationInfoVO> stationInfoVOS = thirdPartyStationRelationService.selectStationList(thirdPartyType);
List<String> stationIdList = stationInfoVOS.stream()
.map(StationInfoVO::getStationId)
.collect(Collectors.toList());
GuiZhouPlatformServiceImpl guiZhouPlatformService = new GuiZhouPlatformServiceImpl();
guiZhouPlatformService.notificationPowerInfo(stationIdList);
//四川省平台推送充电站实时功率
String thirdPartyType2 = ThirdPlatformTypeEnum.SI_CHUAN_PLATFORM.getTypeCode();
List<StationInfoVO> stationInfoVOS2 = thirdPartyStationRelationService.selectStationList(thirdPartyType2);
List<String> stationIdList2 = stationInfoVOS2.stream()
.map(StationInfoVO::getStationId)
.collect(Collectors.toList());
SiChuanPlatformServiceImpl sichuanPlatformService = new SiChuanPlatformServiceImpl();
sichuanPlatformService.notificationPowerInfo(stationIdList2);
}
/**
* 推送统计信息 24小时执行一次
*/
public void pushStatisticsInfo() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 贵州推送充电站统计信息
String thirdPartyType = ThirdPlatformTypeEnum.GUI_ZHOU_PLATFORM.getTypeCode();
List<StationInfoVO> stationInfoVOS = thirdPartyStationRelationService.selectStationList(thirdPartyType);
List<String> stationIdList = stationInfoVOS.stream()
.map(StationInfoVO::getStationId)
.collect(Collectors.toList());
GuiZhouPlatformServiceImpl guiZhouPlatformService = new GuiZhouPlatformServiceImpl();
for (String stationId : stationIdList) {
guiZhouPlatformService.notificationOperationStatsInfo(stationId);
}
//四川省平台推送充电站实时功率
String thirdPartyType2 = ThirdPlatformTypeEnum.SI_CHUAN_PLATFORM.getTypeCode();
List<StationInfoVO> stationInfoVOS2 = thirdPartyStationRelationService.selectStationList(thirdPartyType2);
List<String> stationIdList2 = stationInfoVOS2.stream()
.map(StationInfoVO::getStationId)
.collect(Collectors.toList());
SiChuanPlatformServiceImpl sichuanPlatformService = new SiChuanPlatformServiceImpl();
for (String stationId : stationIdList2) {
sichuanPlatformService.notificationOperationStatsInfo(stationId);
}
}
/**
* 定时任务, 订单分账
* jsowellTask.processOrderSplitting()
*/
public void processOrderSplitting() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询运营商列表
List<PileMerchantInfo> pileMerchantInfos = pileMerchantInfoService.selectPileMerchantInfoList(null);
if (CollectionUtils.isEmpty(pileMerchantInfos)) {
log.info("定时任务,处理订单分账, 未查询到运营商列表,直接返回");
return;
}
// 获取日期
LocalDate yesterday = LocalDate.now().plusDays(-1);
// 设置挡板8月1号之后的订单按照实际进行分账
// LocalDateTime now = LocalDateTime.now();
// LocalDateTime dateTime = LocalDateTime.of(2023, 8, 2, 0, 0, 0);
// if (now.isBefore(dateTime)) {
// log.info("当前时间:{}早于:{}, 不进行分账处理", DateUtils.formatDateTime(now), DateUtils.formatDateTime(dateTime));
// return;
// }
// 调生成运营商日报方法
pileMerchantInfos.parallelStream().forEach(merchant -> {
try {
orderBasicInfoService.orderSplittingOperations(merchant.getId() + "", yesterday.toString());
} catch (Exception e) {
log.error("生成运营商日报异常, merchantId:{}", merchant.getId(), e);
}
});
}
/**
* 生成运营商日报表
* jsowellTask.generateMerchantBill()
*
*
*/
public void generateMerchantBill() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询运营商列表
List<PileMerchantInfo> pileMerchantInfos = pileMerchantInfoService.selectPileMerchantInfoList(null);
if (CollectionUtils.isEmpty(pileMerchantInfos)) {
log.info("定时任务,处理订单分账, 未查询到运营商列表,直接返回");
return;
}
// 获取日期
LocalDate yesterday = LocalDate.now().plusDays(-1);
// 调生成运营商日报方法
pileMerchantInfos.parallelStream().forEach(merchant -> {
try {
orderBasicInfoService.generateMerchantBill(merchant.getId() + "", yesterday.toString());
} catch (Exception e) {
log.error("生成运营商日报异常, merchantId:{}", merchant.getId(), e);
}
});
}
/**
* 定时任务,自动提现
* jsowellTask.automaticPayouts()
*/
public void automaticPayouts() {
String env = SpringUtils.getActiveProfile();
if (StringUtils.equalsIgnoreCase(env, "pre")) {
log.debug("PRE环境不执行");
return;
}
// 查询开启自动提现运营商列表
// List<PileMerchantInfo> pileMerchantInfos = pileMerchantInfoService.selectPileMerchantInfoList(null);
List<PileMerchantInfo> pileMerchantInfos = pileMerchantInfoService.selectAutoWithdrawalMerchantInfoList();
if (CollectionUtils.isEmpty(pileMerchantInfos)) {
log.info("定时任务,自动提现, 未查询到运营商列表,直接返回");
return;
}
// 调提现方法
pileMerchantInfos.parallelStream().forEach(merchant -> {
try {
WithdrawDTO dto = new WithdrawDTO();
dto.setMerchantId(merchant.getId() + "");
dto.setFeeAmt("0");
adapayService.drawCash(dto);
} catch (Exception e) {
log.error("生成运营商日报异常, merchantId:{}", merchant.getId(), e);
}
});
}
/**
* 处理未分帐订单
* jsowellTask.processUnSettledOrder()
*/
public void processUnSettledOrder() {
String startTime = "2023-01-01 00:00:00";
String endTime = "2024-12-31 23:59:59";
// 使用redis控制请求api
Boolean setnx = redisCache.setnx(CacheConstants.PROCESS_UNSPLIT_ORDERS, Constants.ONE, 65);
if (!setnx) {
return;
}
// 查询未分帐订单
PageUtils.startPage(1, 10);
List<OrderUnsplitRecord> list = orderUnsplitRecordService.queryUnsplitOrders(startTime, endTime);
log.info("处理未分帐订单start, 当前时间:{}, 查询出[{}]条未分账订单, 下面进行处理", DateUtils.getDateTime(), list.size());
int count = 0;
for (OrderUnsplitRecord orderUnsplitRecord : list) {
String paymentId = orderUnsplitRecord.getPaymentId();
String orderCode = orderUnsplitRecord.getOrderCode();
BigDecimal confirmAmt = orderUnsplitRecord.getSettleAmount();
DivMember divMember = new DivMember();
divMember.setMemberId(Constants.ZERO); // 若是商户本身时传入0
divMember.setAmount(AdapayUtil.formatAmount(confirmAmt));
divMember.setFeeFlag(Constants.Y);
PaymentConfirmParam param = PaymentConfirmParam.builder()
.paymentId(paymentId)
.divMemberList(Lists.newArrayList(divMember))
.confirmAmt(confirmAmt)
.orderCode(orderCode)
.wechatAppId(Constants.DEFAULT_APP_ID) // 默认使用万车充的appId
.build();
// 延时分账使用确认交易API
PaymentConfirmResponse paymentConfirmResponse = adapayService.createPaymentConfirmRequest(param);
// 如果确认交易成功,则更新订单状态为已分账
if (paymentConfirmResponse.isSuccess()) {
count++;
orderUnsplitRecord.setStatus(AdapayStatusEnum.SUCCEEDED.getValue());
orderUnsplitRecordService.updateOrderUnsplitRecord(orderUnsplitRecord);
log.info("processUnsplitOrders, 分账成功, paymentId:{}", paymentId);
} else {
// error_type:api_error, error_code:confirm_amt_over_limit, error_msg当前确认金额 > 支付金额 - 已支付确认金额 - 已支付撤销金额
if (paymentConfirmResponse.getError_code().equals("confirm_amt_over_limit")) {
// 查询paymentId的总分账金额
BigDecimal totalSplitAmount;
try {
totalSplitAmount = adapayService.getTotalSplitAmountByPaymentId(paymentId);
} catch (BaseAdaPayException e) {
throw new RuntimeException(e);
}
if (totalSplitAmount.compareTo(confirmAmt) == 0) {
// 如果总分账金额等于当前分账金额,则更新订单状态为已分账
orderUnsplitRecord.setStatus(AdapayStatusEnum.SUCCEEDED.getValue());
orderUnsplitRecordService.updateOrderUnsplitRecord(orderUnsplitRecord);
log.info("processUnsplitOrders, 分账成功, paymentId:{}", paymentId);
} else {
log.info("processUnsplitOrders, 分账失败, paymentId:{}, 错误信息:{}", paymentId, paymentConfirmResponse.getError_msg());
}
}
// error_type:invalid_request_error, error_code:payment_over_time_doing, error_msg:数据正在处理中,请稍后再试
if (paymentConfirmResponse.getError_code().equals("payment_over_time_doing")) {
log.info("processUnsplitOrders, 分账失败, paymentId:{}, 错误信息:{}", paymentId, paymentConfirmResponse.getError_msg());
break;
}
// error_type:invalid_request_error, error_code:refund_repeate_request, error_msg:请求过于频繁
if (paymentConfirmResponse.getError_code().equals("refund_repeate_request")) {
log.info("processUnsplitOrders, 分账失败, paymentId:{}, 错误信息:{}", paymentId, paymentConfirmResponse.getError_msg());
break;
}
}
}
log.info("处理未分帐订单end, 当前时间:[{}], 成功分账[{}]条订单", DateUtils.getDateTime(), count);
}
}