From 64464568546b827fc5778a20efb347bf56ba34ac Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期三, 30 九月 2026 11:05:05 +0800
Subject: [PATCH] 修改充电流程
---
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/support/ChargeAccountSupport.java | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 159 insertions(+), 0 deletions(-)
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/support/ChargeAccountSupport.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/support/ChargeAccountSupport.java
index b57c6fd..695e368 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/support/ChargeAccountSupport.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/support/ChargeAccountSupport.java
@@ -1,5 +1,6 @@
package com.ruoyi.order.support;
+import com.alibaba.fastjson2.JSON;
import com.ruoyi.account.api.feignClient.CompanyAllocateRecordClient;
import com.ruoyi.chargingPile.api.dto.TBillingTemplateDTO;
import com.ruoyi.chargingPile.api.feignClient.AccountingStrategyDetailClient;
@@ -8,6 +9,7 @@
import com.ruoyi.chargingPile.api.model.TBillingTemplateDetail;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.other.api.domain.TGroupCompany;
import com.ruoyi.other.api.dto.ChargeAuthorizationDTO;
import com.ruoyi.other.api.dto.ChargeTimeRange;
@@ -163,6 +165,61 @@
public String getFailReason() {
return failReason;
+ }
+ }
+
+ /**
+ * 企业优惠快照载体(建单时固化 / 结算与补偿时解析的结果):
+ * 与既有 CompanyPreferentialDTO + TBillingTemplateDTO 调用点同构(getPreferentialType/getServiceDiscountRate/
+ * getBillingTemplateId 方法名保持一致),三链路优惠计算代码仅需把数据来源从 Feign 实时查询改为本解析结果,
+ * 计算逻辑不变。
+ */
+ public static class PreferentialSnapshot {
+ /** 优惠方式(1=不优惠,2=按比例优惠,3=按优惠单价收费;null=无优惠配置) */
+ private final Integer preferentialType;
+ /** 服务费优惠比例(%,方式2) */
+ private final BigDecimal serviceDiscountRate;
+ /** 计费模板ID(方式3) */
+ private final Integer billingTemplateId;
+ /** 方式3计费模板(订单快照反序列化或实时查询结果) */
+ private final TBillingTemplateDTO template;
+ /** 订单快照为空、本次为实时查询所得(结算链路需回填订单快照列,保证补偿重算口径一致) */
+ private final boolean fromRealtimeQuery;
+
+ public PreferentialSnapshot(Integer preferentialType, BigDecimal serviceDiscountRate, Integer billingTemplateId,
+ TBillingTemplateDTO template, boolean fromRealtimeQuery) {
+ this.preferentialType = preferentialType;
+ this.serviceDiscountRate = serviceDiscountRate;
+ this.billingTemplateId = billingTemplateId;
+ this.template = template;
+ this.fromRealtimeQuery = fromRealtimeQuery;
+ }
+
+ public Integer getPreferentialType() {
+ return preferentialType;
+ }
+
+ public BigDecimal getServiceDiscountRate() {
+ return serviceDiscountRate;
+ }
+
+ public Integer getBillingTemplateId() {
+ return billingTemplateId;
+ }
+
+ public TBillingTemplateDTO getTemplate() {
+ return template;
+ }
+
+ public boolean isFromRealtimeQuery() {
+ return fromRealtimeQuery;
+ }
+
+ /**
+ * 是否需要把本次解析结果回填到订单快照列(订单快照为空且实时解析到了配置)
+ */
+ public boolean needBackfill() {
+ return fromRealtimeQuery && preferentialType != null;
}
}
@@ -335,6 +392,108 @@
}
/**
+ * 建单时固化企业优惠快照:读取当前生效的公司优惠设置(方式3连带加载计费模板明细),
+ * 供调用方写入订单 preferential_* 快照列;未配置或查询失败返回 null(结算时按实时查询兼容)。
+ */
+ public PreferentialSnapshot snapshotPreferential(Integer companyId) {
+ CompanyPreferentialDTO preferential = loadCompanyPreferential(companyId);
+ if (preferential == null) {
+ return null;
+ }
+ return new PreferentialSnapshot(preferential.getPreferentialType(), preferential.getServiceDiscountRate(),
+ preferential.getBillingTemplateId(), loadBillingTemplate(preferential), false);
+ }
+
+ /**
+ * 建单时把当前生效的企业优惠设置写入订单快照字段(含方式3模板明细JSON,未配置/查询失败时不落快照)
+ */
+ public void fillPreferentialSnapshot(TChargingOrder order, Integer companyId) {
+ if (order == null) {
+ return;
+ }
+ PreferentialSnapshot snapshot = snapshotPreferential(companyId);
+ if (snapshot == null || snapshot.getPreferentialType() == null) {
+ return;
+ }
+ order.setPreferentialType(snapshot.getPreferentialType());
+ order.setServiceDiscountRate(snapshot.getServiceDiscountRate());
+ order.setBillingTemplateId(snapshot.getBillingTemplateId());
+ order.setBillingTemplateSnapshot(serializeTemplateSnapshot(snapshot.getTemplate()));
+ order.setPreferentialSnapshotTime(LocalDateTime.now());
+ }
+
+ /**
+ * 结算/补偿时解析企业优惠:订单快照优先(建单后策略变更不影响本单口径),
+ * 快照为空(历史订单)才实时查询并标记回填;返回 null 表示无优惠配置(按不优惠结算)。
+ */
+ public PreferentialSnapshot resolvePreferential(TChargingOrder order) {
+ if (order != null && order.getPreferentialType() != null) {
+ TBillingTemplateDTO template = null;
+ if (Integer.valueOf(PREFERENTIAL_TYPE_TEMPLATE).equals(order.getPreferentialType())) {
+ template = parseTemplateSnapshot(order.getBillingTemplateSnapshot());
+ if (template == null && order.getBillingTemplateId() != null) {
+ // 快照JSON缺失(历史订单/序列化失败)按模板ID实时查询兜底,尽量不倒退回原价
+ template = loadTemplateById(order.getBillingTemplateId());
+ }
+ }
+ return new PreferentialSnapshot(order.getPreferentialType(), order.getServiceDiscountRate(),
+ order.getBillingTemplateId(), template, false);
+ }
+ CompanyPreferentialDTO preferential = loadCompanyPreferential(order == null ? null : order.getCompanyId());
+ if (preferential == null) {
+ return null;
+ }
+ return new PreferentialSnapshot(preferential.getPreferentialType(), preferential.getServiceDiscountRate(),
+ preferential.getBillingTemplateId(), loadBillingTemplate(preferential), true);
+ }
+
+ /**
+ * 计费模板明细序列化为订单快照JSON(方式3建单固化:模板后续被改动/删除不影响本单结算与补偿口径)
+ */
+ public static String serializeTemplateSnapshot(TBillingTemplateDTO template) {
+ if (template == null) {
+ return null;
+ }
+ try {
+ return JSON.toJSONString(template);
+ } catch (Exception ex) {
+ log.error("[充电优惠] 计费模板快照序列化失败 templateId={}", template.getId(), ex);
+ return null;
+ }
+ }
+
+ /**
+ * 订单快照JSON反序列化为计费模板(失败返回 null,由调用方按模板ID实时查询或按原价兜底)
+ */
+ public static TBillingTemplateDTO parseTemplateSnapshot(String snapshotJson) {
+ if (StringUtils.isEmpty(snapshotJson)) {
+ return null;
+ }
+ try {
+ return JSON.parseObject(snapshotJson, TBillingTemplateDTO.class);
+ } catch (Exception ex) {
+ log.error("[充电优惠] 计费模板快照反序列化失败,按模板ID实时查询兜底", ex);
+ return null;
+ }
+ }
+
+ /**
+ * 按模板ID查询计费模板(仅方式3快照兜底使用,取不到时该段按原价结算)
+ */
+ public TBillingTemplateDTO loadTemplateById(Integer templateId) {
+ if (templateId == null) {
+ return null;
+ }
+ try {
+ R<TBillingTemplateDTO> result = billingTemplateClient.getTemplateDetail(templateId);
+ return result == null ? null : result.getData();
+ } catch (Exception ex) {
+ log.error("[充电优惠] 查询计费模板失败,按原价结算 templateId={}", templateId, ex);
+ return null;
+ }
+ }
+
+ /**
* 服务费按比例优惠:最终单价 = 原价 × (1 - 折扣率/100),折扣率缺失或越界时按原价
*/
public static BigDecimal applyServiceDiscountRate(BigDecimal servicePrice, BigDecimal discountRate) {
--
Gitblit v1.7.1