longz
2026-07-15 c207fd1454b64f47e2e66cd2f578a2b21b06f019
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package com.ruoyi.order.service.impl;
 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.api.model.TChargingOrderShareRecord;
import com.ruoyi.payment.api.vo.IcbcPaymentResp;
import com.ruoyi.payment.api.vo.IcbcRefundReq;
import com.ruoyi.payment.api.vo.IcbcSubOrderQueryReq;
import com.ruoyi.payment.api.vo.IcbcSubOrderRefundReq;
 
import java.math.BigDecimal;
 
final class IcbcAdminFundOperationSupport {
    private IcbcAdminFundOperationSupport() {
    }
 
    static void validateOrder(TChargingOrder order) {
        validateIcbcOrder(order);
        if (!Integer.valueOf(2).equals(order.getRechargePaymentStatus())) {
            throw new IllegalArgumentException("订单尚未支付成功");
        }
    }
 
    static void validateIcbcOrder(TChargingOrder order) {
        if (order == null) {
            throw new IllegalArgumentException("充电订单不存在");
        }
        if (!"ICBC".equals(order.getSourceName())) {
            throw new IllegalArgumentException("仅支持工商银行支付订单");
        }
    }
 
    static boolean isBankPaid(IcbcPaymentResp payment) {
        if (payment == null) {
            return false;
        }
        try {
            JSONObject response = JSON.parseObject(payment.getRawResponse());
            if (response != null && response.getIntValue("returnCode") == 0
                    && "0".equals(response.getString("pay_status"))) {
                return true;
            }
        } catch (Exception ignored) {
        }
        return "0".equals(payment.getStatus());
    }
 
    static BigDecimal requireAmount(BigDecimal amount) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("操作金额必须大于0");
        }
        if (amount.stripTrailingZeros().scale() > 2) {
            throw new IllegalArgumentException("操作金额最多保留两位小数");
        }
        BigDecimal normalized = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
        if (normalized.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("操作金额必须大于0");
        }
        return normalized;
    }
 
    static String buildPendingRefundValue(String operationToken, BigDecimal amount) {
        if (isBlank(operationToken)) {
            throw new IllegalArgumentException("退款流水号不能为空");
        }
        return operationToken + "|" + requireAmount(amount).toPlainString();
    }
 
    static String resolveRefundNo(String pendingValue, BigDecimal amount, String newOperationToken) {
        BigDecimal normalized = requireAmount(amount);
        if (isBlank(pendingValue)) {
            return newOperationToken;
        }
        int separator = pendingValue.lastIndexOf('|');
        if (separator <= 0 || separator == pendingValue.length() - 1) {
            throw new IllegalArgumentException("退款幂等记录格式错误");
        }
        BigDecimal pendingAmount;
        try {
            pendingAmount = new BigDecimal(pendingValue.substring(separator + 1));
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("退款幂等记录格式错误");
        }
        if (pendingAmount.compareTo(normalized) != 0) {
            throw new IllegalArgumentException("上一笔退款结果未知,请按原金额重试");
        }
        return pendingValue.substring(0, separator);
    }
 
    static boolean shouldClearPendingRefund(boolean reusedPending, String status, boolean definitiveResponse) {
        return "SUCCESS".equals(status) || (!reusedPending && definitiveResponse);
    }
 
    static IcbcRefundReq buildRefundRequest(TChargingOrder order, BigDecimal amount, String outRefundNo) {
        validateOrder(order);
        IcbcRefundReq request = new IcbcRefundReq();
        request.setOutTradeNo(order.getCode());
        request.setOrderId(order.getRechargeSerialNumber());
        request.setOutRefundNo(outRefundNo);
        request.setRefundAmount(requireAmount(amount));
        request.setTotalAmount(order.getThirdPayAmount());
        request.setReason("管理后台工行退款");
        return request;
    }
 
    static IcbcSubOrderQueryReq buildSubOrderQueryRequest(TChargingOrder order, TChargingOrderShareRecord shareRecord) {
        validateOrder(order);
        validateShareRecord(order, shareRecord);
        IcbcSubOrderQueryReq request = new IcbcSubOrderQueryReq();
        request.setOrderNoType("2");
        request.setMerOrderId(order.getCode());
        request.setPrtiId(shareRecord.getOriMerId());
        request.setQueryType("1");
        request.setMerTrnscSerno(shareRecord.getSubOrderId());
        request.setSubPrtiId(shareRecord.getSubMerId());
        return request;
    }
 
    static IcbcSubOrderRefundReq buildSubOrderRefundRequest(TChargingOrder order,
                                                             TChargingOrderShareRecord shareRecord,
                                                             BigDecimal amount,
                                                             String retSubOrderId,
                                                             String outtrxSerialNo) {
        validateOrder(order);
        validateShareRecord(order, shareRecord);
        if (Boolean.TRUE.equals(shareRecord.getDelFlag())) {
            throw new IllegalArgumentException("分账记录已删除");
        }
        if (!"SUCCESS".equals(shareRecord.getOnlineShareStatus())) {
            throw new IllegalArgumentException("仅支持已成功的工行分账记录退款");
        }
        if (shareRecord.getOriTrxDate() == null
                || isBlank(shareRecord.getSubMerId()) || isBlank(shareRecord.getSubMerPrtclNo())) {
            throw new IllegalArgumentException("分账记录缺少工行退款参数");
        }
        IcbcSubOrderRefundReq request = new IcbcSubOrderRefundReq();
        request.setChargingOrderCode(order.getCode());
        request.setSeqNo(firstNotBlank(shareRecord.getSeqNo(), order.getCode()));
        request.setBusiType(firstNotBlank(shareRecord.getBusiType(), "1"));
        request.setOriMerId(shareRecord.getOriMerId());
        request.setOriTrxDate(shareRecord.getOriTrxDate() == null ? null : shareRecord.getOriTrxDate().toString());
        request.setSubOrderId(shareRecord.getSubOrderId());
        request.setRetSubOrderId(retSubOrderId);
        request.setOuttrxSerialNo(outtrxSerialNo);
        request.setSubMerId(shareRecord.getSubMerId());
        request.setSubMerPrtclNo(shareRecord.getSubMerPrtclNo());
        request.setRefundAmount(requireAmount(amount));
        request.setMerAcct(shareRecord.getMerAcct());
        request.setMerSpInfor("管理后台工行分账退款");
        return request;
    }
 
    private static void validateShareRecord(TChargingOrder order, TChargingOrderShareRecord shareRecord) {
        if (shareRecord == null || !order.getId().equals(shareRecord.getChargingOrderId())) {
            throw new IllegalArgumentException("分账记录不属于当前订单");
        }
        if (!"ICBC".equals(shareRecord.getPayChannel())) {
            throw new IllegalArgumentException("仅支持工商银行分账记录");
        }
        if (shareRecord.getSubOrderId() == null || shareRecord.getSubOrderId().trim().isEmpty()) {
            throw new IllegalArgumentException("分账记录缺少工行子订单号");
        }
    }
 
    private static boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }
 
    private static String firstNotBlank(String... values) {
        for (String value : values) {
            if (!isBlank(value)) {
                return value;
            }
        }
        return null;
    }
}