| | |
| | | && ChronoUnit.MILLIS.between(createTime, LocalDateTime.now()) > NO_DEVICE_DATA_TIMEOUT_MILLIS; |
| | | } |
| | | |
| | | /** |
| | | * 企业账户订单是否已完成闭环(已结算 settle_status=1 或锁定额度已释放 lock_released=1): |
| | | * 兜底扫描不回退这类订单重跑,避免结算完成后被回退重跑造成重复结算与重复扣款。 |
| | | */ |
| | | static boolean isEnterpriseOrderSettledOrReleased(TChargingOrder order) { |
| | | return null != order |
| | | && (Integer.valueOf(1).equals(order.getSettleStatus()) |
| | | || Integer.valueOf(1).equals(order.getLockReleased())); |
| | | } |
| | | |
| | | |
| | | //十分钟循环执行的定时任务 |
| | | @Scheduled(fixedRate = 1000 * 60 * 10) |
| | |
| | | log.info("定时任务执行,查询到启动失败的订单,执行退款:{}", order.getCode()); |
| | | if(1 == order.getOrderSource()){ |
| | | chargingOrderService.refund(order.getCode()); |
| | | int num = 0; |
| | | while (true){ |
| | | TChargingOrderRefund one = chargingOrderRefundService.getOne(new LambdaQueryWrapper<TChargingOrderRefund>().eq(TChargingOrderRefund::getChargingOrderId, order.getId())); |
| | | if(null != one && 2 == one.getRefundStatus()){ |
| | | order.setStatus(-1); |
| | | chargingOrderService.updateById(order); |
| | | break; |
| | | } |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (InterruptedException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | num++; |
| | | if(num > 30){ |
| | | break; |
| | | //企业账户订单启动失败不落退款明细(资金来自企业额度,仅释放额度并终结),无需等待退款记录,直接终结 |
| | | if (chargingOrderService.isWhitelistEnterpriseOrder(order)) { |
| | | order.setStatus(-1); |
| | | chargingOrderService.updateById(order); |
| | | } else { |
| | | int num = 0; |
| | | while (true){ |
| | | TChargingOrderRefund one = chargingOrderRefundService.getOne(new LambdaQueryWrapper<TChargingOrderRefund>().eq(TChargingOrderRefund::getChargingOrderId, order.getId())); |
| | | if(null != one && 2 == one.getRefundStatus()){ |
| | | order.setStatus(-1); |
| | | chargingOrderService.updateById(order); |
| | | break; |
| | | } |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (InterruptedException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | num++; |
| | | if(num > 30){ |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | }else{ |
| | |
| | | R r = chargingOrderService.endChargeBillingCharge(vo); |
| | | log.info("定时任务执行,停止中的订单处理结果:{}", JSON.toJSONString(r)); |
| | | }else{ |
| | | endOrder(order); |
| | | if (chargingOrderService.isWhitelistEnterpriseOrder(order) |
| | | && shouldFallbackSettle(null, order.getCreateTime(), false)) { |
| | | // 企业账户订单停止中且长时间无任何设备数据与账单:释放锁定额度并兜底关单(金额0、状态5),避免悬挂 |
| | | chargingOrderService.closeEnterpriseOrderWithoutData(order); |
| | | } else { |
| | | endOrder(order); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | if(System.currentTimeMillis() - createTime.getTime() - (8 * 60 * 60 * 1000) > 1000 * 60 * 10){ |
| | | endOrder(order); |
| | | } |
| | | } else if (chargingOrderService.isWhitelistEnterpriseOrder(order) |
| | | && shouldFallbackSettle(null, order.getCreateTime(), false)) { |
| | | // 企业账户订单长时间无任何实时监控数据(设备未上报/报文丢失)且无账单: |
| | | // 释放企业账户锁定额度并兜底关单(金额0、状态5、结算完成标记),避免订单长期悬挂被反复扫描 |
| | | chargingOrderService.closeEnterpriseOrderWithoutData(order); |
| | | } |
| | | } |
| | | } |
| | |
| | | List<TChargingOrder> endChargingOrder = chargingOrderService.findEndChargingOrder(); |
| | | log.info("定时任务执行,查询到已结束未退款的订单数量:{}", endChargingOrder.size()); |
| | | for (TChargingOrder order : endChargingOrder) { |
| | | // 企业账户订单:已结算(settle_status=1)或锁定额度已释放(lock_released=1)说明已完成闭环, |
| | | // 不再回退状态重跑,避免重复结算与重复扣款(企业账户订单结算不落退款记录,无法靠退款记录过滤) |
| | | if (chargingOrderService.isWhitelistEnterpriseOrder(order) |
| | | && isEnterpriseOrderSettledOrReleased(order)) { |
| | | log.info("定时任务执行,企业账户订单已结算/已终结,跳过回退:{}", order.getCode()); |
| | | continue; |
| | | } |
| | | if(-1 == order.getStatus()){ |
| | | order.setStatus(2); |
| | | } |
| | |
| | | } |
| | | |
| | | //企业账户流程:白名单企业账户订单按企业优惠结算(方式2=服务费比例优惠,方式3=按计费模板同阶段单价) |
| | | //优惠口径优先取订单快照(建单时固化,策略后续变更不影响补偿重算),快照为空的历史订单实时查询并回填 |
| | | boolean enterpriseSettlement = chargingOrderService.isWhitelistEnterpriseOrder(order); |
| | | CompanyPreferentialDTO enterprisePreferential = enterpriseSettlement |
| | | ? chargeAccountSupport.loadCompanyPreferential(order.getCompanyId()) : null; |
| | | ChargeAccountSupport.PreferentialSnapshot enterprisePreferential = enterpriseSettlement |
| | | ? chargeAccountSupport.resolvePreferential(order) : null; |
| | | Integer enterprisePreferentialType = null == enterprisePreferential ? null : enterprisePreferential.getPreferentialType(); |
| | | TBillingTemplateDTO enterpriseTemplate = enterpriseSettlement |
| | | ? chargeAccountSupport.loadBillingTemplate(enterprisePreferential) : null; |
| | | TBillingTemplateDTO enterpriseTemplate = null == enterprisePreferential ? null : enterprisePreferential.getTemplate(); |
| | | BigDecimal enterpriseElectricDiscount = BigDecimal.ZERO; |
| | | BigDecimal enterpriseServiceDiscount = BigDecimal.ZERO; |
| | | |
| | |
| | | if(null != desc){ |
| | | order.setEndSoc(new BigDecimal(desc.getSoc())); |
| | | } |
| | | //企业账户流程:历史订单(快照为空)实时解析的优惠结果回填订单快照列,保证后续补偿重算口径一致; |
| | | //同时置结算完成标记,兜底扫描(findEndChargingOrder)不再回退已结算订单,防止重复结算与重复扣款 |
| | | if (enterpriseSettlement) { |
| | | if (null != enterprisePreferential && enterprisePreferential.needBackfill()) { |
| | | order.setPreferentialType(enterprisePreferential.getPreferentialType()); |
| | | order.setServiceDiscountRate(enterprisePreferential.getServiceDiscountRate()); |
| | | order.setBillingTemplateId(enterprisePreferential.getBillingTemplateId()); |
| | | order.setBillingTemplateSnapshot( |
| | | ChargeAccountSupport.serializeTemplateSnapshot(enterprisePreferential.getTemplate())); |
| | | order.setPreferentialSnapshotTime(LocalDateTime.now()); |
| | | } |
| | | order.setSettleStatus(1); |
| | | } |
| | | chargingOrderService.updateById(order); |
| | | |
| | | //企业账户流程:结算企业额度(按实际消费扣减锁定额度、差额退回企业账户)并写消费流水 |
| | | if (enterpriseSettlement && !chargingOrderService.settleWhitelistEnterpriseAccount(order, payAmount)) { |
| | | // 结算失败回退为停止中,交由补偿任务下一轮重新结算,避免企业额度长期冻结 |
| | | // 结算失败回退为停止中,交由补偿任务下一轮重新结算,避免企业额度长期冻结; |
| | | // 同时清除结算完成标记,保证下一轮补偿仍会处理该订单 |
| | | order.setStatus(4); |
| | | order.setSettleStatus(0); |
| | | chargingOrderService.updateById(order); |
| | | log.error("[CD补偿结算] 企业账户额度结算失败,订单回退停止中等待重试 code={}", order.getCode()); |
| | | return; |