| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735 |
- package com.zsElectric.boot.business.service.impl;
- import cn.hutool.core.util.ObjectUtil;
- import cn.hutool.core.util.StrUtil;
- import com.baomidou.mybatisplus.core.metadata.IPage;
- import com.baomidou.mybatisplus.core.toolkit.Assert;
- import com.baomidou.mybatisplus.core.toolkit.Wrappers;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.zsElectric.boot.business.converter.ChargeOrderInfoConverter;
- import com.zsElectric.boot.business.mapper.*;
- import com.zsElectric.boot.business.mapper.ThirdPartyStationInfoMapper;
- import com.zsElectric.boot.business.model.dto.ChargeOrderInfoExportDTO;
- import com.zsElectric.boot.business.model.entity.*;
- import com.zsElectric.boot.business.model.form.ChargeOrderInfoForm;
- import com.zsElectric.boot.business.model.form.applet.AppInvokeChargeForm;
- import com.zsElectric.boot.business.model.form.applet.AppStopChargeForm;
- import com.zsElectric.boot.business.model.query.ChargeOrderInfoQuery;
- import com.zsElectric.boot.business.model.query.applet.AppChargeOrderInfoQuery;
- import com.zsElectric.boot.business.model.vo.ChargeOrderInfoVO;
- import com.zsElectric.boot.business.model.vo.UserVehicleVO;
- import com.zsElectric.boot.business.model.vo.applet.AppChargeVO;
- import com.zsElectric.boot.business.model.vo.applet.AppUserInfoVO;
- import com.zsElectric.boot.business.service.AppletHomeService;
- import com.zsElectric.boot.business.service.ChargeOrderInfoService;
- import com.zsElectric.boot.business.service.UserAccountService;
- import com.zsElectric.boot.business.service.UserInfoService;
- import com.zsElectric.boot.charging.dto.StartChargingRequestDTO;
- import com.zsElectric.boot.charging.dto.StartChargingResponseVO;
- import com.zsElectric.boot.charging.service.ChargingBusinessService;
- import com.zsElectric.boot.charging.vo.EquipmentAuthResponseVO;
- import com.zsElectric.boot.charging.vo.StopChargingOperationResponseVO;
- import com.zsElectric.boot.common.constant.ConnectivityConstants;
- import com.zsElectric.boot.common.constant.SystemConstants;
- import com.zsElectric.boot.core.exception.BusinessException;
- import com.zsElectric.boot.security.util.SecurityUtils;
- import com.zsElectric.boot.system.mapper.UserMapper;
- import com.zsElectric.boot.system.model.entity.DictItem;
- import com.zsElectric.boot.system.model.entity.User;
- import com.zsElectric.boot.system.service.DictItemService;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Service;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.text.SimpleDateFormat;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.*;
- import com.zsElectric.boot.charging.entity.ThirdPartyChargeStatus;
- import com.zsElectric.boot.charging.entity.ThirdPartyConnectorInfo;
- import com.zsElectric.boot.charging.entity.ThirdPartyStationInfo;
- import com.zsElectric.boot.charging.entity.ThirdPartyEquipmentPricePolicy;
- import com.zsElectric.boot.charging.entity.ThirdPartyPolicyInfo;
- import com.zsElectric.boot.charging.mapper.ThirdPartyChargeStatusMapper;
- import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper;
- import com.zsElectric.boot.charging.mapper.ThirdPartyEquipmentPricePolicyMapper;
- import com.zsElectric.boot.charging.mapper.ThirdPartyPolicyInfoMapper;
- import com.zsElectric.boot.charging.mapper.ThirdPartyApiLogMapper;
- import com.zsElectric.boot.charging.entity.ThirdPartyApiLog;
- import com.zsElectric.boot.common.util.DateUtils;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.JsonNode;
- import org.springframework.transaction.annotation.Transactional;
- import org.redisson.api.RLock;
- import org.redisson.api.RedissonClient;
- import java.util.concurrent.TimeUnit;
- import com.zsElectric.boot.business.model.entity.FirmAccountLog;
- import com.zsElectric.boot.common.util.OkHttpUtil;
- import static com.zsElectric.boot.business.service.WFTOrderService.USER_FUND_LOCK_KEY;
- import static com.zsElectric.boot.business.service.WFTOrderService.USER_FUND_LOCK_EXPIRE;
- /**
- * 充电订单信息服务实现类
- *
- * @author zsElectric
- * @since 2025-12-17 19:13
- */
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMapper, ChargeOrderInfo> implements ChargeOrderInfoService {
- private final ChargeOrderInfoConverter chargeOrderInfoConverter;
- private final ChargingBusinessService chargingBusinessService;
- private final ThirdPartyInfoMapper thirdPartyInfoMapper;
- private final UserInfoMapper userInfoMapper;
- private final FirmInfoMapper firmInfoMapper;
- private final CouponMapper couponMapper;
- private final CouponTemplateMapper couponTemplateMapper;
- private final UserAccountService userAccountService;
- private final AppletHomeService appletHomeService;
- private final UserMapper userMapper;
- private final UserVehicleMapper userVehicleMapper;
- private final ThirdPartyChargeStatusMapper chargeStatusMapper;
- private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
- private final ThirdPartyStationInfoMapper thirdPartyStationInfoMapper;
- private final PolicyFeeMapper policyFeeMapper;
- private final ThirdPartyEquipmentPricePolicyMapper thirdPartyEquipmentPricePolicyMapper;
- private final ThirdPartyPolicyInfoMapper thirdPartyPolicyInfoMapper;
- private final DiscountsActivityMapper discountsActivityMapper;
- private final ThirdPartyApiLogMapper thirdPartyApiLogMapper;
- private final ObjectMapper objectMapper;
- private final DictItemService dictItemService;
- private final RedissonClient redissonClient;
- private final OkHttpUtil okHttpUtil;
- private final FirmAccountLogMapper firmAccountLogMapper;
- //充电订单号前缀
- private final String ORDER_NO_PREFIX = "CD";
- //设备流水号前缀
- private final String EQUIPMENT_NO_PREFIX = "SB";
- /**
- * 获取充电订单信息分页列表
- *
- * @param queryParams 查询参数
- * @return {@link IPage <ChargeOrderInfoVO>} 充电订单信息分页列表
- */
- @Override
- public IPage<ChargeOrderInfoVO> getChargeOrderInfoPage(ChargeOrderInfoQuery queryParams) {
- Page<ChargeOrderInfoVO> pageVO = this.baseMapper.getChargeOrderInfoPage(
- new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
- queryParams
- );
- return pageVO;
- }
-
- /**
- * 获取充电订单信息表单数据
- *
- * @param id 充电订单信息ID
- * @return 充电订单信息表单数据
- */
- @Override
- public ChargeOrderInfoForm getChargeOrderInfoFormData(Long id) {
- ChargeOrderInfo entity = this.getById(id);
- return chargeOrderInfoConverter.toForm(entity);
- }
-
- /**
- * 新增充电订单信息
- *
- * @param formData 充电订单信息表单对象
- * @return 是否新增成功
- */
- @Override
- public boolean saveChargeOrderInfo(ChargeOrderInfoForm formData) {
- ChargeOrderInfo entity = chargeOrderInfoConverter.toEntity(formData);
- return this.save(entity);
- }
-
- /**
- * 更新充电订单信息
- *
- * @param id 充电订单信息ID
- * @param formData 充电订单信息表单对象
- * @return 是否修改成功
- */
- @Override
- public boolean updateChargeOrderInfo(Long id,ChargeOrderInfoForm formData) {
- ChargeOrderInfo entity = chargeOrderInfoConverter.toEntity(formData);
- return this.updateById(entity);
- }
-
- /**
- * 删除充电订单信息
- *
- * @param ids 充电订单信息ID,多个以英文逗号(,)分割
- * @return 是否删除成功
- */
- @Override
- public boolean deleteChargeOrderInfos(String ids) {
- Assert.isTrue(StrUtil.isNotBlank(ids), "删除的充电订单信息数据为空");
- // 逻辑删除
- List<Long> idList = Arrays.stream(ids.split(","))
- .map(Long::parseLong)
- .toList();
- return this.removeByIds(idList);
- }
- @Override
- public IPage<ChargeOrderInfoVO> getPage(AppChargeOrderInfoQuery queryParams) {
- queryParams.setUserId(SecurityUtils.getUserId());
- Page<ChargeOrderInfoVO> pageVO = this.baseMapper.getPage(
- new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
- queryParams
- );
- return pageVO;
- }
- @Override
- public AppChargeVO invokeCharge(AppInvokeChargeForm formData) {
- log.info("启动充电开始,用户ID:{},设备认证流水号:{},充电桩编号:{}", SecurityUtils.getUserId(), formData.getEquipAuthSeq(), formData.getEquipmentId());
- //校验设备占用状态
- chargingBusinessService.checkEquipmentOccupancyStatus(formData.getConnectorId());
- // 渠道方启动充电不需要用户资金锁
- if (Objects.equals(formData.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
- log.info("渠道方启动充电开始,用户ID:{},设备认证流水号:{},充电桩编号:{}", SecurityUtils.getUserId(), formData.getEquipAuthSeq(), formData.getEquipmentId());
- try {
- return channelInvokeCharge(formData);
- } catch (Exception e) {
- log.error("渠道方启动充电失败", e);
- throw new BusinessException("启动充电失败 !" + e.getMessage());
- }
- }
- // 必要校验
- Long userId = SecurityUtils.getUserId();
- Assert.isTrue(userId != null, "用户ID不能为空");
- // 获取用户资金操作统一锁,防止充电启动与退款并发
- String lockKey = USER_FUND_LOCK_KEY + userId;
- RLock lock = redissonClient.getLock(lockKey);
- boolean locked = false;
- try {
- // 尝试获取锁,等待3秒,锁过期时间60秒
- locked = lock.tryLock(3, USER_FUND_LOCK_EXPIRE, TimeUnit.SECONDS);
- if (!locked) {
- log.warn("用户:{}资金操作正在进行中,无法启动充电", userId);
- throw new BusinessException("操作正在进行中,请稍后重试");
- }
- return doInvokeCharge(formData, userId);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new BusinessException("启动充电失败,请稍后重试");
- } finally {
- // 释放锁
- if (locked && lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- }
- /**
- * 执行启动充电逻辑(内部方法)
- */
- private AppChargeVO doInvokeCharge(AppInvokeChargeForm formData, Long userId) {
- try {
- AppChargeVO appInvokeChargeVO = new AppChargeVO();
- AppUserInfoVO userInfo = userInfoMapper.getAppletUserInfo(userId);
- Assert.isTrue(userInfo != null, "用户信息不存在");
- //判断有没有正在进行中的订单
- Long count = this.baseMapper.selectCount(Wrappers.lambdaQuery(ChargeOrderInfo.class).eq(ChargeOrderInfo::getUserId, userId).in(ChargeOrderInfo::getStatus, SystemConstants.STATUS_ZERO, SystemConstants.STATUS_ONE, SystemConstants.STATUS_TWO));
- if (count > 0){
- throw new BusinessException("您有正在进行中的订单,请先停止充电");
- }
- //校验用户余额是否满足起充价(防止充值后立即退款绕过前端校验)
- DictItem upRecharge = dictItemService.getOne(Wrappers.<DictItem>lambdaQuery()
- .eq(DictItem::getDictCode, "up_recharge")
- .last("limit 1")
- );
- if (ObjectUtil.isNotEmpty(upRecharge)) {
- BigDecimal chargeFee = new BigDecimal(upRecharge.getValue());
- UserAccount userAccount = userAccountService.getOne(Wrappers.lambdaQuery(UserAccount.class)
- .eq(UserAccount::getUserId, userId)
- .last("limit 1"));
- if (userAccount == null || userAccount.getBalance().compareTo(chargeFee) < 0) {
- throw new BusinessException("用户余额低于起充值 " + chargeFee + " 元,请前往充值后再充电!");
- }
- }
- //生成系统充电订单号及互联互通充电订单号 startChargeSeq equipAuthSeq (格式"运营商ID+唯一编号")
- String chargeOrderNo = generateNo(ORDER_NO_PREFIX, userId);
- String seq = ConnectivityConstants.OPERATOR_ID + chargeOrderNo;
- //请求设备认证
- EquipmentAuthResponseVO equipmentAuthResponseVO = chargingBusinessService.queryEquipAuth(seq,
- formData.getConnectorId());
- if (Objects.equals(equipmentAuthResponseVO.getSuccStat(), SystemConstants.STATUS_ONE)) {
- throw new BusinessException("设备认证失败,请检查枪是否正确接入充电槽!");
- }else {
- log.info("设备认证成功,设备认证流水号:{}", equipmentAuthResponseVO.getEquipAuthSeq());
- }
- //创建订单
- ChargeOrderInfo chargeOrderInfo = new ChargeOrderInfo();
- chargeOrderInfo.setUserId(userId);
- chargeOrderInfo.setConnectorId(formData.getConnectorId());
- chargeOrderInfo.setEquipmentId(formData.getEquipmentId());
- chargeOrderInfo.setEquipAuthSeq(seq);
- chargeOrderInfo.setChargeOrderNo(chargeOrderNo);
- chargeOrderInfo.setStartChargeSeq(seq);
- chargeOrderInfo.setPhoneNum(userInfo.getPhone());
- chargeOrderInfo.setThirdPartyStationId(formData.getStationId());
- chargeOrderInfo.setOrderType(formData.getOrderType());
- //预支付金额
- BigDecimal preAmt = appletHomeService.calculateAvailableChargingAmount(formData.getConnectorId());
- chargeOrderInfo.setPreAmt(preAmt);
- //渠道方订单设置运营商ID
- if (Objects.equals(formData.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)){
- chargeOrderInfo.setOperatorId(formData.getOperatorId());
- chargeOrderInfo.setPreAmt(formData.getChannelPreAmt());
- }
- //判断用户是否绑定企业
- if (ObjectUtil.isNotEmpty(userInfo.getFirmId())) {
- FirmInfo firmInfo = firmInfoMapper.selectById(userInfo.getFirmId());
- if(firmInfo != null && Objects.equals(firmInfo.getStatus(), SystemConstants.STATUS_ONE)) {
- chargeOrderInfo.setFirmId(firmInfo.getId());
- chargeOrderInfo.setOrderType(SystemConstants.STATUS_ONE);
- }
- }
- //优惠券
- if(ObjectUtil.isNotEmpty(formData.getCouponId())) {
- Coupon coupon = couponMapper.selectById(formData.getCouponId());
- if(coupon != null && Objects.equals(coupon.getStatus(), SystemConstants.STATUS_ONE)) {
- CouponTemplate couponTemplate = couponTemplateMapper.selectById(coupon.getTemplateId());
- chargeOrderInfo.setCouponId(coupon.getId());
- chargeOrderInfo.setCouponPrice(couponTemplate.getDiscountPrice());
- }
- }
- //启动充电
- StartChargingRequestDTO requestDTO = new StartChargingRequestDTO();
- requestDTO
- .setStartChargeSeq(seq)
- .setConnectorID(formData.getConnectorId())
- .setPhoneNum(userInfo.getPhone())
- //预支付金额
- .setChargingAmt(preAmt.toString())
- ;
- //车牌号
- if(ObjectUtil.isNotEmpty(formData.getPlateNum())) {
- chargeOrderInfo.setPlateNum(formData.getPlateNum());
- requestDTO.setPlateNum(formData.getPlateNum());
- }else {
- //获取当前用户的默认车牌号
- UserVehicle userVehicle =
- userVehicleMapper.selectOne(Wrappers.lambdaQuery(UserVehicle.class).eq(UserVehicle::getUserId, userId).eq(UserVehicle::getIsDefault, SystemConstants.STATUS_ONE).last("limit 1"));
- if (ObjectUtil.isNotEmpty(userVehicle)) {
- requestDTO.setPlateNum(userVehicle.getLicensePlate());
- }
- }
- StartChargingResponseVO startChargingResponseVO = chargingBusinessService.startCharging(requestDTO);
- if (!Objects.equals(startChargingResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
- throw new BusinessException(startChargingResponseVO.getFailReasonMsg());
- }
- //保存订单
- this.save(chargeOrderInfo);
- appInvokeChargeVO.setChargeOrderNo(chargeOrderNo);
- appInvokeChargeVO.setChargeOrderId(chargeOrderInfo.getId());
- return appInvokeChargeVO;
- } catch (Exception e) {
- log.error("启动充电失败,系统错误", e);
- throw new BusinessException("启动充电失败 !" + e.getMessage());
- }
- }
- /**
- * 渠道方启动充电
- *
- * @param formData
- * @return
- */
- public AppChargeVO channelInvokeCharge(AppInvokeChargeForm formData) throws JsonProcessingException {
- String seq = ConnectivityConstants.OPERATOR_ID + formData.getChannelOrderNo();
- //请求设备认证
- EquipmentAuthResponseVO equipmentAuthResponseVO = chargingBusinessService.queryEquipAuth(seq,
- formData.getConnectorId());
- if (Objects.equals(equipmentAuthResponseVO.getSuccStat(), SystemConstants.STATUS_ONE)) {
- throw new BusinessException("设备认证失败,请检查枪是否正确接入充电槽!");
- } else {
- log.info("设备认证成功,设备认证流水号:{}", equipmentAuthResponseVO.getEquipAuthSeq());
- }
- //创建订单
- ChargeOrderInfo chargeOrderInfo = new ChargeOrderInfo();
- Long userId = SecurityUtils.getUserId();
- User user = userMapper.selectById(userId);
- if(ObjectUtil.isNotEmpty(user)){
- FirmInfo firmInfo = firmInfoMapper.selectOne(Wrappers.lambdaQuery(FirmInfo.class).eq(FirmInfo::getDeptId, user.getDeptId()).last("limit 1"));
- if(firmInfo != null) {
- chargeOrderInfo.setFirmId(firmInfo.getId());
- }
- }
- if (ObjectUtil.isNotEmpty(formData.getOperatorId())){
- ThirdPartyInfo thirdPartyInfo = thirdPartyInfoMapper.selectOne(
- Wrappers.lambdaQuery(ThirdPartyInfo.class)
- .eq(ThirdPartyInfo::getOperatorId, formData.getOperatorId())
- .last("limit 1"));
- if (thirdPartyInfo != null) {
- UserInfo userInfo = userInfoMapper.selectOne(
- Wrappers.lambdaQuery(UserInfo.class)
- .eq(UserInfo::getPhone, formData.getChannelUserPhone())
- .eq(UserInfo::getThirdPartId, thirdPartyInfo.getId())
- .last("limit 1"));
- if (userInfo != null) {
- chargeOrderInfo.setUserId(userInfo.getId());
- }
- }
- }
- chargeOrderInfo.setOrderType(SystemConstants.CHARGE_ORDER_TYPE_CHANNEL);
- chargeOrderInfo.setConnectorId(formData.getConnectorId());
- chargeOrderInfo.setEquipmentId(formData.getEquipmentId());
- chargeOrderInfo.setEquipAuthSeq(seq);
- chargeOrderInfo.setChargeOrderNo(formData.getChannelOrderNo());
- chargeOrderInfo.setStartChargeSeq(seq);
- chargeOrderInfo.setPhoneNum(formData.getChannelUserPhone());
- chargeOrderInfo.setThirdPartyStationId(formData.getStationId());
- //渠道手机号
- if(ObjectUtil.isNotEmpty(formData.getChannelUserPhone())){
- chargeOrderInfo.setPhoneNum(formData.getChannelUserPhone());
- }
- //预支付金额
- chargeOrderInfo.setPreAmt(formData.getChannelPreAmt());
- //渠道方订单设置运营商ID
- chargeOrderInfo.setOperatorId(formData.getOperatorId());
- //启动充电
- StartChargingRequestDTO requestDTO = new StartChargingRequestDTO();
- requestDTO
- .setStartChargeSeq(seq)
- .setConnectorID(formData.getConnectorId())
- .setPhoneNum(formData.getChannelUserPhone())
- //预支付金额
- .setChargingAmt(formData.getChannelPreAmt().toString());
- //车牌号
- if(ObjectUtil.isNotEmpty(formData.getPlateNum())) {
- chargeOrderInfo.setPlateNum(formData.getPlateNum());
- requestDTO.setPlateNum(formData.getPlateNum());
- }
- StartChargingResponseVO startChargingResponseVO = chargingBusinessService.startCharging(requestDTO);
- if (!Objects.equals(startChargingResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
- throw new BusinessException(startChargingResponseVO.getFailReasonMsg());
- }
- //保存订单
- this.save(chargeOrderInfo);
- AppChargeVO appInvokeChargeVO = new AppChargeVO();
- appInvokeChargeVO.setChargeOrderId(chargeOrderInfo.getId());
- appInvokeChargeVO.setChargeOrderNo(chargeOrderInfo.getChargeOrderNo());
- appInvokeChargeVO.setStatus(SystemConstants.STATUS_ZERO);
- return appInvokeChargeVO;
- }
- @Override
- public AppChargeVO stopCharge(AppStopChargeForm formData) {
- try {
- AppChargeVO appInvokeChargeVO = new AppChargeVO();
- //订单
- ChargeOrderInfo chargeOrderInfo = this.getOne(Wrappers.lambdaQuery(ChargeOrderInfo.class)
- .eq(ChargeOrderInfo::getChargeOrderNo, formData.getChargeOrderNo())
- .eq(StrUtil.isNotBlank(formData.getOperatorId()), ChargeOrderInfo::getOperatorId, formData.getOperatorId())
- .last("limit 1"));
- if(ObjectUtil.isEmpty(chargeOrderInfo)){
- throw new BusinessException("订单不存在");
- }
- StopChargingOperationResponseVO stopChargingOperationResponseVO = chargingBusinessService.stopCharging(chargeOrderInfo.getStartChargeSeq(), chargeOrderInfo.getConnectorId());
- if (!Objects.equals(stopChargingOperationResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
- throw new BusinessException("停止充电失败,请稍后再重试!");
- }
- chargeOrderInfo.setStopType(1); // 1-主动停止
- this.updateById(chargeOrderInfo);
- appInvokeChargeVO.setChargeOrderId(chargeOrderInfo.getId());
- appInvokeChargeVO.setChargeOrderNo(chargeOrderInfo.getChargeOrderNo());
- return appInvokeChargeVO;
- } catch (Exception e) {
- log.error("停止充电失败,系统错误", e);
- throw new BusinessException("停止充电失败,请稍后再重试!");
- }
- }
- @Override
- public void orderSettlement(Long chargeOrderId) {
- ChargeOrderInfo chargeOrderInfo = this.getById(chargeOrderId);
- Long userId = chargeOrderInfo.getUserId();
- //平台收费总金额
- BigDecimal totalCharge = chargeOrderInfo.getRealCost();
- //加积分
- userAccountService.update(Wrappers.lambdaUpdate(UserAccount.class)
- .eq(UserAccount::getUserId, userId)
- .setSql("`integral` = `integral` +" + totalCharge)
- );
- //账户变动及日志记录
- userAccountService.updateAccountBalanceAndLog(
- userId,
- totalCharge,
- SystemConstants.CHANGE_TYPE_REDUCE,
- SystemConstants.CHARGE_DEDUCT_NOTE,
- chargeOrderInfo.getId()
- );
- }
- @Override
- public ChargeOrderInfoVO queryOrder(String chargeOrderNo) {
- return baseMapper.queryOrder(chargeOrderNo);
- }
- /**
- * 获取充电订单信息导出列表
- *
- * @param queryParams 查询参数
- * @return 充电订单信息导出列表
- */
- @Override
- public List<ChargeOrderInfoExportDTO> listExportChargeOrderInfo(ChargeOrderInfoQuery queryParams) {
- return baseMapper.listExportChargeOrderInfo(queryParams);
- }
- /**
- * 创建商户订单号
- * 要求 32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
- * 组成 两位前缀 + 17位时间戳 + 9位id补零 + 4位随机数 合计32位
- *
- * @param head 例如 商品-SP 退款-TK 等等
- * @param id 用户id
- * @return
- */
- public String generateNo(String head, Long id) {
- StringBuilder uid = new StringBuilder(id.toString());
- Date date = new Date();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
- int length = uid.length();
- for (int i = 0; i < 9 - length; i++) {
- uid.insert(0, "0");
- }
- return head + sdf.format(date) + uid + (int) ((Math.random() * 9 + 1) * 1000);
- }
- /**
- * 修复未处理的充电订单
- * 优先通过third_party_api_log表获取推送充电订单信息,
- * 若没有则通过third_party_charge_status表查询total_power>0的数据
- * 重新处理这些订单:更新状态、计算费用、扣减余额
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public String repairUnprocessedOrders() {
- log.info("开始修复未处理的充电订单...");
-
- // 1. 查询状态为5(未成功充电)的订单
- List<ChargeOrderInfo> unprocessedOrders = this.list(Wrappers.<ChargeOrderInfo>lambdaQuery()
- .eq(ChargeOrderInfo::getStatus, 5)
- .isNotNull(ChargeOrderInfo::getStartChargeSeq));
-
- if (unprocessedOrders.isEmpty()) {
- log.info("没有找到需要修复的订单");
- return "没有找到需要修复的订单";
- }
-
- int totalCount = 0;
- int successCount = 0;
- int skipCount = 0;
- int apiLogCount = 0;
- int chargeStatusCount = 0;
- List<String> failedOrders = new ArrayList<>();
-
- for (ChargeOrderInfo order : unprocessedOrders) {
- totalCount++;
- try {
- // 2. 优先从third_party_api_log表查询推送充电订单信息
- ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
- Wrappers.<ThirdPartyApiLog>lambdaQuery()
- .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
- .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
- .orderByDesc(ThirdPartyApiLog::getCreatedTime)
- .last("LIMIT 1"));
-
- if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
- // 使用API日志中的推送数据处理订单
- boolean success = processOrderFromApiLog(order, apiLog);
- if (success) {
- // 设置补偿状态为已补偿
- order.setCompensateStatus(1);
- this.updateById(order);
- successCount++;
- apiLogCount++;
- log.info("订单{}通过API日志修复成功", order.getChargeOrderNo());
- continue;
- }
- }
-
- // 3. 备选方案:从third_party_charge_status表查询
- ThirdPartyChargeStatus chargeStatus = chargeStatusMapper.selectOne(
- Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
- .eq(ThirdPartyChargeStatus::getStartChargeSeq, order.getStartChargeSeq()));
-
- if (chargeStatus == null || chargeStatus.getTotalPower() == null
- || chargeStatus.getTotalPower().compareTo(BigDecimal.ZERO) <= 0) {
- log.info("订单{}无有效充电数据,设置为异常无须补偿", order.getChargeOrderNo());
- // 设置补偿状态为异常无须补偿
- order.setCompensateStatus(2);
- this.updateById(order);
- skipCount++;
- continue;
- }
-
- log.info("开始通过充电状态表修复订单: {}, 充电量: {}", order.getChargeOrderNo(), chargeStatus.getTotalPower());
-
- // 4. 获取站点信息
- ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
- Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
- .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId())
- .last("LIMIT 1"));
- if (connectorInfo == null) {
- log.warn("订单{}找不到充电接口信息", order.getChargeOrderNo());
- failedOrders.add(order.getChargeOrderNo());
- continue;
- }
-
- ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
- Wrappers.<ThirdPartyStationInfo>lambdaQuery()
- .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
- .last("LIMIT 1"));
- if (stationInfo == null) {
- log.warn("订单{}找不到站点信息", order.getChargeOrderNo());
- failedOrders.add(order.getChargeOrderNo());
- continue;
- }
-
- // 5. 设置第三方费用信息
- order.setTotalCharge(chargeStatus.getTotalPower());
- order.setThirdPartyTotalCost(chargeStatus.getTotalMoney() != null ? chargeStatus.getTotalMoney() : BigDecimal.ZERO);
- order.setThirdPartyServerfee(chargeStatus.getServiceMoney() != null ? chargeStatus.getServiceMoney() : BigDecimal.ZERO);
- order.setThirdPartyElecfee(chargeStatus.getElecMoney() != null ? chargeStatus.getElecMoney() : BigDecimal.ZERO);
- if (StrUtil.isNotBlank(chargeStatus.getChargeDetails())) {
- order.setChargeDetails(chargeStatus.getChargeDetails());
- }
-
- // 6. 计算平台服务费
- BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
-
- // 7. 更新订单信息
- order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
- order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
- order.setStatus(SystemConstants.STATUS_THREE); // 已完成
-
- // 设置充电时间
- if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- order.setStartTime(chargeStatus.getStartTime().format(formatter));
- order.setEndTime(chargeStatus.getEndTime().format(formatter));
- order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
- }
-
- // 设置修复备注
- order.setRemark("通过补偿修复处理");
- // 设置补偿状态为已补偿
- order.setCompensateStatus(1);
-
- this.updateById(order);
-
- // 8. 执行账户余额扣减(仅平台订单和企业订单)
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
- || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
- orderSettlement(order.getId());
- log.info("订单{}余额扣减完成", order.getChargeOrderNo());
- }
-
- successCount++;
- chargeStatusCount++;
- log.info("订单{}通过充电状态表修复成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
-
- } catch (Exception e) {
- log.error("修复订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
- failedOrders.add(order.getChargeOrderNo());
- }
- }
-
- String result = String.format("修复完成!总计: %d, 成功: %d (API日志: %d, 充电状态: %d), 跳过: %d, 失败: %d",
- totalCount, successCount, apiLogCount, chargeStatusCount, skipCount, failedOrders.size());
- if (!failedOrders.isEmpty()) {
- result += ", 失败订单: " + String.join(",", failedOrders);
- }
- log.info(result);
- return result;
- }
-
- /**
- * 通过API日志中的推送数据处理订单
- * @param order 订单信息
- * @param apiLog API日志
- * @return 是否处理成功
- */
- private boolean processOrderFromApiLog(ChargeOrderInfo order, ThirdPartyApiLog apiLog) {
- try {
- JsonNode jsonNode = objectMapper.readTree(apiLog.getDecryptedRequestData());
-
- // 解析推送数据
- String startChargeSeq = getJsonTextValue(jsonNode, "StartChargeSeq");
- if (startChargeSeq == null || !startChargeSeq.equals(order.getStartChargeSeq())) {
- log.warn("订单{}的StartChargeSeq不匹配,跳过API日志处理", order.getChargeOrderNo());
- return false;
- }
-
- String totalPowerStr = getJsonTextValue(jsonNode, "TotalPower");
- if (totalPowerStr == null || new BigDecimal(totalPowerStr).compareTo(BigDecimal.ZERO) <= 0) {
- log.info("订单{}的API日志充电量为0,跳过处理", order.getChargeOrderNo());
- return false;
- }
-
- log.info("开始通过API日志修复订单: {}, 充电量: {}", order.getChargeOrderNo(), totalPowerStr);
-
- // 设置充电信息
- order.setTotalCharge(new BigDecimal(totalPowerStr));
- order.setStopReason(getJsonTextValue(jsonNode, "StopReason"));
- order.setStartTime(getJsonTextValue(jsonNode, "StartTime"));
- order.setEndTime(getJsonTextValue(jsonNode, "EndTime"));
- order.setChargeDetails(jsonNode.toString());
-
- // 第三方费用
- String totalMoney = getJsonTextValue(jsonNode, "TotalMoney");
- String totalSeviceMoney = getJsonTextValue(jsonNode, "TotalSeviceMoney");
- String totalElecMoney = getJsonTextValue(jsonNode, "TotalElecMoney");
- order.setThirdPartyTotalCost(totalMoney != null ? new BigDecimal(totalMoney) : BigDecimal.ZERO);
- order.setThirdPartyServerfee(totalSeviceMoney != null ? new BigDecimal(totalSeviceMoney) : BigDecimal.ZERO);
- order.setThirdPartyElecfee(totalElecMoney != null ? new BigDecimal(totalElecMoney) : BigDecimal.ZERO);
-
- // 获取连接器和站点信息
- String connectorId = getJsonTextValue(jsonNode, "ConnectorID");
- if (connectorId == null) {
- connectorId = order.getConnectorId();
- }
-
- ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
- Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
- .eq(ThirdPartyConnectorInfo::getConnectorId, connectorId)
- .last("LIMIT 1"));
- if (connectorInfo == null) {
- log.warn("订单{}找不到充电接口信息", order.getChargeOrderNo());
- return false;
- }
-
- ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
- Wrappers.<ThirdPartyStationInfo>lambdaQuery()
- .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
- .last("LIMIT 1"));
- if (stationInfo == null) {
- log.warn("订单{}找不到站点信息", order.getChargeOrderNo());
- return false;
- }
-
- // 计算平台服务费(从ChargeDetails中解析)
- BigDecimal serviceFee = calculateServiceFeeFromChargeDetails(order, jsonNode, stationInfo);
-
- // 更新订单信息
- order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
- order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
- order.setStatus(SystemConstants.STATUS_THREE); // 已完成
-
- // 计算充电时间
- if (order.getStartTime() != null && order.getEndTime() != null) {
- order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
- }
-
- // 设置修复备注
- order.setRemark("通过补偿修复处理");
-
- this.updateById(order);
-
- // 执行账户余额扣减(仅平台订单和企业订单)
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
- || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
- orderSettlement(order.getId());
- log.info("订单{}余额扣减完成", order.getChargeOrderNo());
- }
-
- log.info("订单{}通过API日志处理成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
- return true;
-
- } catch (Exception e) {
- log.error("通过API日志处理订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
- return false;
- }
- }
-
- /**
- * 从ChargeDetails计算平台服务费
- */
- private BigDecimal calculateServiceFeeFromChargeDetails(ChargeOrderInfo order, JsonNode jsonNode,
- ThirdPartyStationInfo stationInfo) {
- BigDecimal serviceFee = BigDecimal.ZERO;
-
- JsonNode chargeDetails = jsonNode.get("ChargeDetails");
- if (chargeDetails != null && chargeDetails.isArray()) {
- for (JsonNode node : chargeDetails) {
- String itemFlag = getJsonTextValue(node, "ItemFlag");
- String detailPowerStr = getJsonTextValue(node, "DetailPower");
-
- if (itemFlag != null && detailPowerStr != null) {
- BigDecimal detailPower = new BigDecimal(detailPowerStr);
- PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
- .eq(PolicyFee::getStationInfoId, stationInfo.getId())
- .eq(PolicyFee::getPeriodFlag, Integer.parseInt(itemFlag))
- .last("LIMIT 1"));
- if (policyFee != null && policyFee.getOpFee() != null) {
- serviceFee = serviceFee.add(policyFee.getOpFee().multiply(detailPower));
- }
- }
- }
- } else {
- // 无明细时,使用最高费用时段计算
- log.info("订单{}无充电明细,使用简化计算", order.getChargeOrderNo());
- ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
- Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
- .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, order.getConnectorId())
- .last("LIMIT 1"));
- if (pricePolicy != null) {
- List<ThirdPartyPolicyInfo> policyInfos = thirdPartyPolicyInfoMapper.selectList(
- Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
- .eq(ThirdPartyPolicyInfo::getPricePolicyId, pricePolicy.getId())
- .eq(ThirdPartyPolicyInfo::getIsDeleted, 0));
- PolicyFee maxPolicyFee = null;
- for (ThirdPartyPolicyInfo policyInfo : policyInfos) {
- PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
- .eq(PolicyFee::getStationInfoId, stationInfo.getId())
- .eq(PolicyFee::getPeriodFlag, policyInfo.getPeriodFlag())
- .last("LIMIT 1"));
- if (policyFee != null && policyFee.getOpFee() != null) {
- if (maxPolicyFee == null || policyFee.getOpFee().compareTo(maxPolicyFee.getOpFee()) > 0) {
- maxPolicyFee = policyFee;
- }
- }
- }
- if (maxPolicyFee != null) {
- serviceFee = maxPolicyFee.getOpFee().multiply(order.getTotalCharge());
- }
- }
- }
-
- return serviceFee;
- }
-
- /**
- * 安全获取JSON节点的文本值
- */
- private String getJsonTextValue(JsonNode node, String fieldName) {
- if (node == null || !node.has(fieldName) || node.get(fieldName).isNull()) {
- return null;
- }
- return node.get(fieldName).asText();
- }
-
- /**
- * 计算平台服务费
- */
- private BigDecimal calculateServiceFee(ChargeOrderInfo order, ThirdPartyChargeStatus chargeStatus,
- ThirdPartyStationInfo stationInfo) {
- BigDecimal serviceFee = BigDecimal.ZERO;
-
- // 查询价格策略
- ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
- Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
- .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, chargeStatus.getConnectorId())
- .last("LIMIT 1"));
-
- if (pricePolicy == null) {
- log.warn("订单{}找不到价格策略", order.getChargeOrderNo());
- return serviceFee;
- }
-
- // 查询时段信息
- List<ThirdPartyPolicyInfo> allPolicyInfos = thirdPartyPolicyInfoMapper.selectList(
- Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
- .eq(ThirdPartyPolicyInfo::getPricePolicyId, pricePolicy.getId())
- .eq(ThirdPartyPolicyInfo::getIsDeleted, 0)
- .orderByAsc(ThirdPartyPolicyInfo::getStartTime));
-
- if (allPolicyInfos.isEmpty()) {
- log.warn("订单{}找不到时段信息", order.getChargeOrderNo());
- return serviceFee;
- }
-
- // 根据充电时间段匹配费用
- if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
- String chargeStartTimeStr = chargeStatus.getStartTime().format(DateTimeFormatter.ofPattern("HHmmss"));
- String chargeEndTimeStr = chargeStatus.getEndTime().format(DateTimeFormatter.ofPattern("HHmmss"));
-
- // 找到充电时间跨越的所有时段,使用最高费用时段计算
- PolicyFee maxPolicyFee = null;
- for (ThirdPartyPolicyInfo policyInfo : allPolicyInfos) {
- if (chargeStartTimeStr.compareTo(policyInfo.getStartTime()) >= 0
- || chargeEndTimeStr.compareTo(policyInfo.getStartTime()) >= 0) {
- PolicyFee policyFee = policyFeeMapper.selectOne(
- Wrappers.<PolicyFee>lambdaQuery()
- .eq(PolicyFee::getStationInfoId, stationInfo.getId())
- .eq(PolicyFee::getPeriodFlag, policyInfo.getPeriodFlag())
- .last("LIMIT 1"));
- if (policyFee != null && policyFee.getOpFee() != null) {
- if (maxPolicyFee == null || policyFee.getOpFee().compareTo(maxPolicyFee.getOpFee()) > 0) {
- maxPolicyFee = policyFee;
- }
- }
- }
- }
-
- if (maxPolicyFee != null) {
- serviceFee = maxPolicyFee.getOpFee().multiply(order.getTotalCharge());
- }
- }
-
- return serviceFee;
- }
- /**
- * 根据充电订单号修复已完成订单
- * 修复状态为3(已完成)的订单,重新处理订单状态变更、数据修改及余额扣减
- * 优先通过third_party_api_log表获取推送数据,备选通过third_party_charge_status表查询
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public String repairOrderByOrderNo(String chargeOrderNo) {
- log.info("开始根据订单号修复订单: {}", chargeOrderNo);
-
- // 1. 查询订单
- ChargeOrderInfo order = this.getOne(Wrappers.<ChargeOrderInfo>lambdaQuery()
- .eq(ChargeOrderInfo::getChargeOrderNo, chargeOrderNo)
- .last("LIMIT 1"));
-
- if (order == null) {
- return "订单不存在: " + chargeOrderNo;
- }
-
- log.info("开始修复订单: {}, 当前状态: {}", chargeOrderNo, order.getStatus());
-
- // 2. 检查订单是否需要修复(只有充电度数、平台费用、三方费用同时为0扏null的订单才处理)
- boolean needRepair = isZeroOrNull(order.getTotalCharge())
- && isZeroOrNull(order.getRealCost())
- && isZeroOrNull(order.getRealServiceCost())
- && isZeroOrNull(order.getThirdPartyTotalCost())
- && isZeroOrNull(order.getThirdPartyServerfee());
-
- if (!needRepair) {
- return "订单" + chargeOrderNo + "已有充电数据,无需修复。充电度数:" + order.getTotalCharge()
- + ", 平台收取金额:" + order.getRealCost()
- + ", 平台服务费:" + order.getRealServiceCost()
- + ", 三方消费总额:" + order.getThirdPartyTotalCost()
- + ", 三方服务费:" + order.getThirdPartyServerfee();
- }
-
- if (order.getStartChargeSeq() == null) {
- return "订单缺少StartChargeSeq,无法修复";
- }
-
- try {
- // 3. 优先从third_party_api_log表查询推送充电订单信息
- ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
- Wrappers.<ThirdPartyApiLog>lambdaQuery()
- .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
- .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
- .orderByDesc(ThirdPartyApiLog::getCreatedTime)
- .last("LIMIT 1"));
-
- if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
- // 使用API日志中的推送数据处理订单
- boolean success = repairOrderFromApiLogByOrderNo(order, apiLog);
- if (success) {
- // 设置补偿状态为已补偿
- order.setCompensateStatus(1);
- this.updateById(order);
- log.info("订单{}通过API日志修复成功", chargeOrderNo);
- return "订单" + chargeOrderNo + "通过API日志修复成功,实际费用: " + order.getRealCost();
- }
- }
-
- // 4. 备选方案:从third_party_charge_status表查询
- ThirdPartyChargeStatus chargeStatus = chargeStatusMapper.selectOne(
- Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
- .eq(ThirdPartyChargeStatus::getStartChargeSeq, order.getStartChargeSeq()));
-
- if (chargeStatus == null || chargeStatus.getTotalPower() == null
- || chargeStatus.getTotalPower().compareTo(BigDecimal.ZERO) <= 0) {
- // 设置补偿状态为异常无须补偿
- order.setCompensateStatus(2);
- this.updateById(order);
- return "订单" + chargeOrderNo + "无有效充电数据,设置为异常无须补偿";
- }
-
- log.info("开始通过充电状态表修复订单: {}, 充电量: {}", chargeOrderNo, chargeStatus.getTotalPower());
-
- // 5. 获取站点信息
- ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
- Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
- .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId())
- .last("LIMIT 1"));
- if (connectorInfo == null) {
- return "订单" + chargeOrderNo + "找不到充电接口信息";
- }
-
- ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
- Wrappers.<ThirdPartyStationInfo>lambdaQuery()
- .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
- .last("LIMIT 1"));
- if (stationInfo == null) {
- return "订单" + chargeOrderNo + "找不到站点信息";
- }
-
- // 6. 设置第三方费用信息
- order.setTotalCharge(chargeStatus.getTotalPower());
- order.setThirdPartyTotalCost(chargeStatus.getTotalMoney() != null ? chargeStatus.getTotalMoney() : BigDecimal.ZERO);
- order.setThirdPartyServerfee(chargeStatus.getServiceMoney() != null ? chargeStatus.getServiceMoney() : BigDecimal.ZERO);
- order.setThirdPartyElecfee(chargeStatus.getElecMoney() != null ? chargeStatus.getElecMoney() : BigDecimal.ZERO);
- if (StrUtil.isNotBlank(chargeStatus.getChargeDetails())) {
- order.setChargeDetails(chargeStatus.getChargeDetails());
- }
-
- // 7. 计算平台服务费
- BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
-
- // 8. 更新订单信息
- order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
- order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
-
- // 设置充电时间
- if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- order.setStartTime(chargeStatus.getStartTime().format(formatter));
- order.setEndTime(chargeStatus.getEndTime().format(formatter));
- order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
- }
-
- // 设置修复备注
- order.setRemark("通过补偿修复处理");
- // 设置补偿状态为已补偿
- order.setCompensateStatus(1);
-
- this.updateById(order);
-
- // 9. 执行账户余额扣减(仅平台订单和企业订单)
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
- || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
- orderSettlement(order.getId());
- log.info("订单{}余额扣减完成", chargeOrderNo);
- }
-
- log.info("订单{}通过充电状态表修复成功,实际费用: {}", chargeOrderNo, order.getRealCost());
- return "订单" + chargeOrderNo + "通过充电状态表修复成功,实际费用: " + order.getRealCost();
-
- } catch (Exception e) {
- log.error("修复订单{}失败: {}", chargeOrderNo, e.getMessage(), e);
- throw new BusinessException("修复订单失败: " + e.getMessage());
- }
- }
-
- /**
- * 通过API日志修复单个订单(根据订单号)
- * @param order 订单信息
- * @param apiLog API日志
- * @return 是否处理成功
- */
- private boolean repairOrderFromApiLogByOrderNo(ChargeOrderInfo order, ThirdPartyApiLog apiLog) {
- try {
- JsonNode jsonNode = objectMapper.readTree(apiLog.getDecryptedRequestData());
-
- // 解析推送数据
- String startChargeSeq = getJsonTextValue(jsonNode, "StartChargeSeq");
- if (startChargeSeq == null || !startChargeSeq.equals(order.getStartChargeSeq())) {
- log.warn("订单{}的StartChargeSeq不匹配,跳过API日志处理", order.getChargeOrderNo());
- return false;
- }
-
- String totalPowerStr = getJsonTextValue(jsonNode, "TotalPower");
- if (totalPowerStr == null || new BigDecimal(totalPowerStr).compareTo(BigDecimal.ZERO) <= 0) {
- log.info("订单{}的API日志充电量为0,跳过处理", order.getChargeOrderNo());
- return false;
- }
-
- log.info("开始通过API日志修复订单: {}, 充电量: {}", order.getChargeOrderNo(), totalPowerStr);
-
- // 设置充电信息
- order.setTotalCharge(new BigDecimal(totalPowerStr));
- order.setStopReason(getJsonTextValue(jsonNode, "StopReason"));
- order.setStartTime(getJsonTextValue(jsonNode, "StartTime"));
- order.setEndTime(getJsonTextValue(jsonNode, "EndTime"));
- order.setChargeDetails(jsonNode.toString());
-
- // 第三方费用
- String totalMoney = getJsonTextValue(jsonNode, "TotalMoney");
- String totalSeviceMoney = getJsonTextValue(jsonNode, "TotalSeviceMoney");
- String totalElecMoney = getJsonTextValue(jsonNode, "TotalElecMoney");
- order.setThirdPartyTotalCost(totalMoney != null ? new BigDecimal(totalMoney) : BigDecimal.ZERO);
- order.setThirdPartyServerfee(totalSeviceMoney != null ? new BigDecimal(totalSeviceMoney) : BigDecimal.ZERO);
- order.setThirdPartyElecfee(totalElecMoney != null ? new BigDecimal(totalElecMoney) : BigDecimal.ZERO);
-
- // 获取连接器和站点信息
- String connectorId = getJsonTextValue(jsonNode, "ConnectorID");
- if (connectorId == null) {
- connectorId = order.getConnectorId();
- }
-
- ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
- Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
- .eq(ThirdPartyConnectorInfo::getConnectorId, connectorId)
- .last("LIMIT 1"));
- if (connectorInfo == null) {
- log.warn("订单{}找不到充电接口信息", order.getChargeOrderNo());
- return false;
- }
-
- ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
- Wrappers.<ThirdPartyStationInfo>lambdaQuery()
- .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
- .last("LIMIT 1"));
- if (stationInfo == null) {
- log.warn("订单{}找不到站点信息", order.getChargeOrderNo());
- return false;
- }
-
- // 计算平台服务费(从ChargeDetails中解析)
- BigDecimal serviceFee = calculateServiceFeeFromChargeDetails(order, jsonNode, stationInfo);
-
- // 更新订单信息
- order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
- order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
-
- // 计算充电时间
- if (order.getStartTime() != null && order.getEndTime() != null) {
- order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
- }
-
- // 设置修复备注
- order.setRemark("通过补偿修复处理");
-
- this.updateById(order);
-
- // 执行账户余额扣减(仅平台订单和企业订单)
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
- || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
- orderSettlement(order.getId());
- log.info("订单{}余额扣减完成", order.getChargeOrderNo());
- }
- // 渠道方订单:推送充电订单信息 + 渠道方账户余额扣减
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
- compensateChannelOrder(order, apiLog.getDecryptedRequestData());
- }
-
- log.info("订单{}通过API日志处理成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
- return true;
-
- } catch (Exception e) {
- log.error("通过API日志处理订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
- return false;
- }
- }
-
- /**
- * 判断BigDecimal是否为null或0
- * @param value 要判断的值
- * @return 如果为null或0返回true,否则返回false
- */
- private boolean isZeroOrNull(BigDecimal value) {
- return value == null || value.compareTo(BigDecimal.ZERO) == 0;
- }
- /**
- * 补偿未处理的充电订单(定时任务调用)
- * 查找状态为3(已完成)或5(未成功充电)且充电数据为0的订单
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public String compensateUnprocessedOrders() {
- log.info("开始执行充电订单补偿定时任务...");
-
- // 1. 查询状态为3(已完成)或5(未成功充电)且充电数据为0的订单
- List<ChargeOrderInfo> unprocessedOrders = this.list(Wrappers.<ChargeOrderInfo>lambdaQuery()
- .in(ChargeOrderInfo::getStatus, 3, 5)
- .isNotNull(ChargeOrderInfo::getStartChargeSeq)
- // 充电度数为0或null
- .and(wrapper -> wrapper
- .isNull(ChargeOrderInfo::getTotalCharge)
- .or()
- .eq(ChargeOrderInfo::getTotalCharge, BigDecimal.ZERO))
- // 平台实际收取金额为0或null
- .and(wrapper -> wrapper
- .isNull(ChargeOrderInfo::getRealCost)
- .or()
- .eq(ChargeOrderInfo::getRealCost, BigDecimal.ZERO))
- // 平台总服务费为0或null
- .and(wrapper -> wrapper
- .isNull(ChargeOrderInfo::getRealServiceCost)
- .or()
- .eq(ChargeOrderInfo::getRealServiceCost, BigDecimal.ZERO))
- // 三方充电消费总额为0或null
- .and(wrapper -> wrapper
- .isNull(ChargeOrderInfo::getThirdPartyTotalCost)
- .or()
- .eq(ChargeOrderInfo::getThirdPartyTotalCost, BigDecimal.ZERO))
- // 三方充电服务费为0或null
- .and(wrapper -> wrapper
- .isNull(ChargeOrderInfo::getThirdPartyServerfee)
- .or()
- .eq(ChargeOrderInfo::getThirdPartyServerfee, BigDecimal.ZERO))
- // 补偿状态为0或null
- .and(wrapper -> wrapper
- .isNull(ChargeOrderInfo::getCompensateStatus)
- .or()
- .eq(ChargeOrderInfo::getCompensateStatus, 0))
- );
-
- if (unprocessedOrders.isEmpty()) {
- log.info("充电订单补偿定时任务: 没有找到需要补偿的订单");
- return "没有找到需要补偿的订单";
- }
-
- log.info("充电订单补偿定时任务: 找到{}个需要补偿的订单", unprocessedOrders.size());
-
- int totalCount = 0;
- int successCount = 0;
- int skipCount = 0;
- int apiLogCount = 0;
- int chargeStatusCount = 0;
- List<String> failedOrders = new ArrayList<>();
-
- for (ChargeOrderInfo order : unprocessedOrders) {
- totalCount++;
- try {
- // 2. 优先从third_party_api_log表查询推送充电订单信息
- ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
- Wrappers.<ThirdPartyApiLog>lambdaQuery()
- .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
- .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
- .orderByDesc(ThirdPartyApiLog::getCreatedTime)
- .last("LIMIT 1"));
-
- if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
- // 使用API日志中的推送数据处理订单
- boolean success = processOrderFromApiLog(order, apiLog);
- if (success) {
- // 设置补偿状态为已补偿
- order.setCompensateStatus(1);
- this.updateById(order);
- successCount++;
- apiLogCount++;
- log.info("补偿任务: 订单{}通过API日志补偿成功", order.getChargeOrderNo());
- continue;
- }
- }
-
- // 3. 备选方案:从third_party_charge_status表查询
- ThirdPartyChargeStatus chargeStatus = chargeStatusMapper.selectOne(
- Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
- .eq(ThirdPartyChargeStatus::getStartChargeSeq, order.getStartChargeSeq()));
-
- if (chargeStatus == null || chargeStatus.getTotalPower() == null
- || chargeStatus.getTotalPower().compareTo(BigDecimal.ZERO) <= 0) {
- log.info("补偿任务: 订单{}无有效充电数据,设置为异常无须补偿", order.getChargeOrderNo());
- // 设置补偿状态为异常无须补偿
- order.setCompensateStatus(2);
- this.updateById(order);
- skipCount++;
- continue;
- }
-
- log.info("补偿任务: 开始通过充电状态表补偿订单: {}, 充电量: {}", order.getChargeOrderNo(), chargeStatus.getTotalPower());
-
- // 4. 获取站点信息
- ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
- Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
- .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId())
- .last("LIMIT 1"));
- if (connectorInfo == null) {
- log.warn("补偿任务: 订单{}找不到充电接口信息", order.getChargeOrderNo());
- failedOrders.add(order.getChargeOrderNo());
- continue;
- }
-
- ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
- Wrappers.<ThirdPartyStationInfo>lambdaQuery()
- .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
- .last("LIMIT 1"));
- if (stationInfo == null) {
- log.warn("补偿任务: 订单{}找不到站点信息", order.getChargeOrderNo());
- failedOrders.add(order.getChargeOrderNo());
- continue;
- }
-
- // 5. 设置第三方费用信息
- order.setTotalCharge(chargeStatus.getTotalPower());
- order.setThirdPartyTotalCost(chargeStatus.getTotalMoney() != null ? chargeStatus.getTotalMoney() : BigDecimal.ZERO);
- order.setThirdPartyServerfee(chargeStatus.getServiceMoney() != null ? chargeStatus.getServiceMoney() : BigDecimal.ZERO);
- order.setThirdPartyElecfee(chargeStatus.getElecMoney() != null ? chargeStatus.getElecMoney() : BigDecimal.ZERO);
- if (StrUtil.isNotBlank(chargeStatus.getChargeDetails())) {
- order.setChargeDetails(chargeStatus.getChargeDetails());
- }
-
- // 6. 计算平台服务费
- BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
-
- // 7. 更新订单信息
- order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
- order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
- order.setStatus(SystemConstants.STATUS_THREE); // 已完成
-
- // 设置充电时间
- if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- order.setStartTime(chargeStatus.getStartTime().format(formatter));
- order.setEndTime(chargeStatus.getEndTime().format(formatter));
- order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
- }
-
- // 设置修复备注
- order.setRemark("通过补偿修复处理");
-
- this.updateById(order);
-
- // 8. 执行账户余额扣减(仅平台订单和企业订单)
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
- || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
- orderSettlement(order.getId());
- log.info("补偿任务: 订单{}余额扣减完成", order.getChargeOrderNo());
- }
- // 渠道方订单:推送充电订单信息 + 渠道方账户余额扣减
- if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
- compensateChannelOrder(order, null);
- }
-
- successCount++;
- chargeStatusCount++;
- log.info("补偿任务: 订单{}通过充电状态表补偿成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
-
- } catch (Exception e) {
- log.error("补偿任务: 补偿订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
- failedOrders.add(order.getChargeOrderNo());
- }
- }
-
- String result = String.format("充电订单补偿完成!总计: %d, 成功: %d (API日志: %d, 充电状态: %d), 跳过: %d, 失败: %d",
- totalCount, successCount, apiLogCount, chargeStatusCount, skipCount, failedOrders.size());
- if (!failedOrders.isEmpty()) {
- result += ", 失败订单: " + String.join(",", failedOrders);
- }
- log.info(result);
- return result;
- }
- /**
- * 渠道方订单补偿:推送充电订单信息给渠道方 + 渠道方账户余额扣减
- * 推送失败只记日志,不回滚补偿
- *
- * @param order 补偿完成的订单
- * @param apiLogData API日志原始数据(可为null,则从订单字段构建推送数据)
- */
- private void compensateChannelOrder(ChargeOrderInfo order, String apiLogData) {
- try {
- FirmInfo firmInfo = firmInfoMapper.selectById(order.getFirmId());
- if (firmInfo == null) {
- log.warn("补偿任务: 订单{}找不到渠道方信息,firmId: {}", order.getChargeOrderNo(), order.getFirmId());
- return;
- }
- // 1. 推送充电订单信息给渠道方
- pushChargeOrderInfoToChannel(order, firmInfo, apiLogData);
- // 2. 渠道方账户余额扣减
- deductChannelFirmBalance(order, firmInfo);
- } catch (Exception e) {
- log.error("补偿任务: 渠道方订单{}补偿处理异常: {}", order.getChargeOrderNo(), e.getMessage(), e);
- }
- }
- /**
- * 推送充电订单信息给渠道方(参考 /notification_charge_order_info 接口推送格式)
- * 失败只记日志,不影响补偿结果
- */
- private void pushChargeOrderInfoToChannel(ChargeOrderInfo order, FirmInfo firmInfo, String apiLogData) {
- try {
- // 构建推送数据
- Map<String, Object> pushData;
- if (apiLogData != null) {
- // 使用API日志原始数据
- pushData = objectMapper.readValue(apiLogData, Map.class);
- } else {
- // 从order字段构建推送数据
- pushData = buildCompensationPushData(order);
- }
- normalizeCompensationPushData(pushData, order);
- pushData.put("chargeOrderNo", order.getChargeOrderNo());
- String url = firmInfo.getChannelUrl() + "/notification_charge_order_info";
- String pushJson = objectMapper.writeValueAsString(pushData);
- int maxRetries = 3;
- int retryIntervalMs = 5000;
- for (int attempt = 1; attempt <= maxRetries; attempt++) {
- try {
- JsonNode response = okHttpUtil.doPostJson(url, pushJson, null);
- log.info("补偿任务: 渠道方推送充电订单信息成功 - chargeOrderNo: {}, firmId: {}, response: {}",
- order.getChargeOrderNo(), order.getFirmId(), response);
- return;
- } catch (Exception e) {
- log.error("补偿任务: 渠道方推送充电订单信息失败(第{}次) - chargeOrderNo: {}, firmId: {}, url: {}, 错误: {}",
- attempt, order.getChargeOrderNo(), order.getFirmId(), url, e.getMessage(), e);
- if (attempt < maxRetries) {
- try {
- Thread.sleep(retryIntervalMs);
- } catch (InterruptedException ie) {
- Thread.currentThread().interrupt();
- break;
- }
- }
- }
- }
- } catch (Exception e) {
- log.error("补偿任务: 构建渠道方推送数据失败 - chargeOrderNo: {}, 错误: {}", order.getChargeOrderNo(), e.getMessage(), e);
- }
- }
- /**
- * 渠道方账户余额扣减 + 记录资金流水
- */
- private Map<String, Object> buildCompensationPushData(ChargeOrderInfo order) throws JsonProcessingException {
- Map<String, Object> pushData = new LinkedHashMap<>();
- if (StrUtil.isNotBlank(order.getChargeDetails())) {
- JsonNode chargeDetailsNode = objectMapper.readTree(order.getChargeDetails());
- if (chargeDetailsNode.isObject()) {
- pushData.putAll(objectMapper.convertValue(chargeDetailsNode, LinkedHashMap.class));
- } else if (chargeDetailsNode.isArray()) {
- pushData.put("ChargeDetails", objectMapper.convertValue(chargeDetailsNode, List.class));
- }
- }
- normalizeCompensationPushData(pushData, order);
- return pushData;
- }
- private void normalizeCompensationPushData(Map<String, Object> pushData, ChargeOrderInfo order) throws JsonProcessingException {
- List<Map<String, Object>> chargeDetails = resolveChargeDetails(pushData, order);
- putIfBlank(pushData, "ArrearsAmt", BigDecimal.ZERO);
- pushData.put("ChargeDetails", chargeDetails);
- pushData.put("SumPeriod", chargeDetails.size());
- putIfBlank(pushData, "ConnectorID", order.getConnectorId());
- putIfBlank(pushData, "EndTime", order.getEndTime());
- putIfBlank(pushData, "OriginElecMoney", defaultDecimal(order.getThirdPartyElecfee()));
- putIfBlank(pushData, "OriginMoney", defaultDecimal(order.getThirdPartyTotalCost()));
- putIfBlank(pushData, "OriginServiceMoney", defaultDecimal(order.getThirdPartyServerfee()));
- putIfBlank(pushData, "PlatOrderId", order.getId());
- putIfBlank(pushData, "ReceiptsAmt", defaultDecimal(order.getThirdPartyTotalCost()));
- putIfBlank(pushData, "StartChargeSeq", order.getStartChargeSeq());
- putIfBlank(pushData, "StartTime", order.getStartTime());
- putIfBlank(pushData, "StopReason", parseIntegerOrDefault(order.getStopReason(), 0));
- putIfBlank(pushData, "TotalElecMoney", defaultDecimal(order.getThirdPartyElecfee()));
- putIfBlank(pushData, "TotalMoney", defaultDecimal(order.getThirdPartyTotalCost()));
- putIfBlank(pushData, "TotalPower", defaultDecimal(order.getTotalCharge()));
- putIfBlank(pushData, "TotalSeviceMoney", defaultDecimal(order.getThirdPartyServerfee()));
- }
- private List<Map<String, Object>> resolveChargeDetails(Map<String, Object> pushData, ChargeOrderInfo order) throws JsonProcessingException {
- List<Map<String, Object>> chargeDetails = convertChargeDetails(pushData.get("ChargeDetails"));
- if (!chargeDetails.isEmpty()) {
- return chargeDetails;
- }
- if (StrUtil.isNotBlank(order.getChargeDetails())) {
- JsonNode chargeDetailsNode = objectMapper.readTree(order.getChargeDetails());
- if (chargeDetailsNode.isArray()) {
- chargeDetails = convertChargeDetails(chargeDetailsNode);
- } else if (chargeDetailsNode.isObject() && chargeDetailsNode.has("ChargeDetails")) {
- chargeDetails = convertChargeDetails(chargeDetailsNode.get("ChargeDetails"));
- }
- }
- if (!chargeDetails.isEmpty()) {
- return chargeDetails;
- }
- return buildFallbackChargeDetails(order);
- }
- private List<Map<String, Object>> convertChargeDetails(Object rawChargeDetails) {
- if (rawChargeDetails == null) {
- return new ArrayList<>();
- }
- List<Map<String, Object>> chargeDetails = new ArrayList<>();
- if (rawChargeDetails instanceof JsonNode jsonNode && jsonNode.isArray()) {
- for (JsonNode detailNode : jsonNode) {
- chargeDetails.add(objectMapper.convertValue(detailNode, LinkedHashMap.class));
- }
- return chargeDetails;
- }
- if (rawChargeDetails instanceof List<?> detailList) {
- for (Object detail : detailList) {
- chargeDetails.add(objectMapper.convertValue(detail, LinkedHashMap.class));
- }
- }
- return chargeDetails;
- }
- private List<Map<String, Object>> buildFallbackChargeDetails(ChargeOrderInfo order) {
- List<Map<String, Object>> chargeDetails = new ArrayList<>();
- if (order == null) {
- return chargeDetails;
- }
- Map<String, Object> detail = new LinkedHashMap<>();
- BigDecimal totalPower = defaultDecimal(order.getTotalCharge());
- BigDecimal totalElecMoney = defaultDecimal(order.getThirdPartyElecfee());
- BigDecimal totalServiceMoney = defaultDecimal(order.getThirdPartyServerfee());
- detail.put("DetailStartTime", order.getStartTime());
- detail.put("DetailEndTime", order.getEndTime());
- detail.put("ItemFlag", resolvePeriodFlag(order));
- detail.put("ElecPrice", calculateUnitPrice(totalElecMoney, totalPower));
- detail.put("SevicePrice", calculateUnitPrice(totalServiceMoney, totalPower));
- detail.put("DetailPower", totalPower);
- detail.put("DetailElecMoney", totalElecMoney);
- detail.put("DetailSeviceMoney", totalServiceMoney);
- chargeDetails.add(detail);
- return chargeDetails;
- }
- private Integer resolvePeriodFlag(ChargeOrderInfo order) {
- if (order == null || StrUtil.isBlank(order.getConnectorId())) {
- return 3;
- }
- ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
- Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
- .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, order.getConnectorId())
- .eq(ThirdPartyEquipmentPricePolicy::getIsDeleted, 0)
- .last("LIMIT 1"));
- if (pricePolicy == null) {
- return 3;
- }
- List<ThirdPartyPolicyInfo> policyInfos = thirdPartyPolicyInfoMapper.selectList(
- Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
- .eq(ThirdPartyPolicyInfo::getPricePolicyId, pricePolicy.getId())
- .eq(ThirdPartyPolicyInfo::getIsDeleted, 0)
- .orderByAsc(ThirdPartyPolicyInfo::getStartTime));
- if (policyInfos == null || policyInfos.isEmpty()) {
- return 3;
- }
- String chargeStartTime = extractTimePart(order.getStartTime());
- if (StrUtil.isBlank(chargeStartTime)) {
- return policyInfos.get(0).getPeriodFlag() != null ? policyInfos.get(0).getPeriodFlag() : 3;
- }
- ThirdPartyPolicyInfo matchedPolicy = null;
- for (ThirdPartyPolicyInfo policyInfo : policyInfos) {
- if (policyInfo.getStartTime() == null) {
- continue;
- }
- if (chargeStartTime.compareTo(policyInfo.getStartTime()) >= 0) {
- matchedPolicy = policyInfo;
- } else {
- break;
- }
- }
- if (matchedPolicy == null) {
- matchedPolicy = policyInfos.get(policyInfos.size() - 1);
- }
- return matchedPolicy.getPeriodFlag() != null ? matchedPolicy.getPeriodFlag() : 3;
- }
- private String extractTimePart(String dateTime) {
- if (StrUtil.isBlank(dateTime)) {
- return null;
- }
- try {
- return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
- .format(DateTimeFormatter.ofPattern("HHmmss"));
- } catch (Exception ex) {
- return null;
- }
- }
- private BigDecimal calculateUnitPrice(BigDecimal amount, BigDecimal power) {
- if (power == null || power.compareTo(BigDecimal.ZERO) <= 0) {
- return BigDecimal.ZERO;
- }
- return amount.divide(power, 4, RoundingMode.HALF_UP);
- }
- private BigDecimal defaultDecimal(BigDecimal value) {
- return value != null ? value : BigDecimal.ZERO;
- }
- private void putIfBlank(Map<String, Object> data, String key, Object value) {
- if (!data.containsKey(key) || isNullLikeValue(data.get(key))) {
- data.put(key, value);
- }
- }
- private boolean isNullLikeValue(Object value) {
- if (value == null) {
- return true;
- }
- if (value instanceof String str) {
- return StrUtil.isBlank(str) || "null".equalsIgnoreCase(str.trim());
- }
- return false;
- }
- private Integer parseIntegerOrDefault(String value, Integer defaultValue) {
- if (StrUtil.isBlank(value) || "null".equalsIgnoreCase(value.trim())) {
- return defaultValue;
- }
- try {
- return Integer.parseInt(value.trim());
- } catch (NumberFormatException ex) {
- return defaultValue;
- }
- }
- private void deductChannelFirmBalance(ChargeOrderInfo order, FirmInfo firmInfo) {
- BigDecimal cost = order.getRealCost();
- if (cost == null || cost.compareTo(BigDecimal.ZERO) <= 0) {
- log.info("补偿任务: 订单{}实际费用为0,跳过渠道方余额扣减", order.getChargeOrderNo());
- return;
- }
- // 记录资金流水
- FirmAccountLog accountLog = new FirmAccountLog();
- accountLog.setFirmId(firmInfo.getId());
- accountLog.setFirmType(firmInfo.getFirmType());
- accountLog.setEventDesc("渠道方充电订单下账(补偿)");
- accountLog.setSerialNo(order.getChargeOrderNo());
- accountLog.setIncomeType(2);
- accountLog.setBeforeChange(firmInfo.getBalance());
- accountLog.setAfterChange(firmInfo.getBalance().subtract(cost));
- accountLog.setMoneyChange(cost);
- firmAccountLogMapper.insert(accountLog);
- // 渠道方账户余额修改
- firmInfo.setBalance(firmInfo.getBalance().subtract(cost));
- firmInfoMapper.updateById(firmInfo);
- log.info("补偿任务: 订单{}渠道方余额扣减完成,扣减金额: {}, 扣减后余额: {}",
- order.getChargeOrderNo(), cost, firmInfo.getBalance());
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public String compensateChannelOrderPush() {
- log.info("开始执行渠道方订单推送补偿...");
- // 查询已完成(status=3)、备注为"通过补偿修复处理"的渠道方订单
- List<ChargeOrderInfo> channelOrders = this.list(Wrappers.<ChargeOrderInfo>lambdaQuery()
- .eq(ChargeOrderInfo::getStatus, 3)
- .eq(ChargeOrderInfo::getOrderType, SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)
- .eq(ChargeOrderInfo::getRemark, "通过补偿修复处理")
- );
- if (channelOrders.isEmpty()) {
- log.info("渠道方推送补偿: 没有找到需要补偿的渠道方订单");
- return "没有找到需要补偿的渠道方订单";
- }
- log.info("渠道方推送补偿: 找到{}个需要补偿的渠道方订单", channelOrders.size());
- int totalCount = 0;
- int successCount = 0;
- List<String> failedOrders = new ArrayList<>();
- for (ChargeOrderInfo order : channelOrders) {
- totalCount++;
- try {
- // 优先从third_party_api_log获取原始推送数据
- String apiLogData = null;
- if (order.getStartChargeSeq() != null) {
- ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
- Wrappers.<ThirdPartyApiLog>lambdaQuery()
- .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
- .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
- .orderByDesc(ThirdPartyApiLog::getCreatedTime)
- .last("LIMIT 1"));
- if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
- apiLogData = apiLog.getDecryptedRequestData();
- }
- }
- compensateChannelOrder(order, apiLogData);
- successCount++;
- log.info("渠道方推送补偿: 订单{}补偿成功", order.getChargeOrderNo());
- } catch (Exception e) {
- log.error("渠道方推送补偿: 订单{}补偿失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
- failedOrders.add(order.getChargeOrderNo());
- }
- }
- String result = String.format("渠道方推送补偿完成!总计: %d, 成功: %d, 失败: %d",
- totalCount, successCount, failedOrders.size());
- if (!failedOrders.isEmpty()) {
- result += ", 失败订单: " + String.join(",", failedOrders);
- }
- log.info(result);
- return result;
- }
- }
|