|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+package com.water.revenue.service;
|
|
|
2
|
+
|
|
|
3
|
+import lombok.RequiredArgsConstructor;
|
|
|
4
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
5
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
6
|
+import org.springframework.stereotype.Service;
|
|
|
7
|
+
|
|
|
8
|
+import java.math.BigDecimal;
|
|
|
9
|
+import java.time.LocalDate;
|
|
|
10
|
+import java.time.format.DateTimeFormatter;
|
|
|
11
|
+import java.util.*;
|
|
|
12
|
+
|
|
|
13
|
+@Slf4j
|
|
|
14
|
+@Service
|
|
|
15
|
+@RequiredArgsConstructor
|
|
|
16
|
+public class RevenueQueryService {
|
|
|
17
|
+
|
|
|
18
|
+ private final JdbcTemplate jdbcTemplate;
|
|
|
19
|
+
|
|
|
20
|
+ /**
|
|
|
21
|
+ * 多维度账单查询
|
|
|
22
|
+ */
|
|
|
23
|
+ public Map<String, Object> queryBills(Map<String, Object> filters) {
|
|
|
24
|
+ log.info("Querying bills with filters: {}", filters);
|
|
|
25
|
+
|
|
|
26
|
+ StringBuilder sql = new StringBuilder(
|
|
|
27
|
+ "SELECT b.*, c.customer_name, c.customer_no, c.area, c.customer_type, m.meter_no " +
|
|
|
28
|
+ "FROM rev_bill b " +
|
|
|
29
|
+ "JOIN rev_customer c ON b.customer_id = c.id " +
|
|
|
30
|
+ "JOIN rev_meter m ON b.meter_id = m.id " +
|
|
|
31
|
+ "WHERE 1=1");
|
|
|
32
|
+
|
|
|
33
|
+ List<Object> params = new ArrayList<>();
|
|
|
34
|
+
|
|
|
35
|
+ // 时间范围
|
|
|
36
|
+ if (filters.get("startDate") != null) {
|
|
|
37
|
+ sql.append(" AND b.created_at >= ?::timestamp");
|
|
|
38
|
+ params.add(filters.get("startDate"));
|
|
|
39
|
+ }
|
|
|
40
|
+ if (filters.get("endDate") != null) {
|
|
|
41
|
+ sql.append(" AND b.created_at <= ?::timestamp");
|
|
|
42
|
+ params.add(filters.get("endDate"));
|
|
|
43
|
+ }
|
|
|
44
|
+
|
|
|
45
|
+ // 区域
|
|
|
46
|
+ if (filters.get("area") != null && !filters.get("area").toString().isEmpty()) {
|
|
|
47
|
+ sql.append(" AND c.area = ?");
|
|
|
48
|
+ params.add(filters.get("area"));
|
|
|
49
|
+ }
|
|
|
50
|
+
|
|
|
51
|
+ // 客户类型
|
|
|
52
|
+ if (filters.get("customerType") != null && !filters.get("customerType").toString().isEmpty()) {
|
|
|
53
|
+ sql.append(" AND c.customer_type = ?");
|
|
|
54
|
+ params.add(filters.get("customerType"));
|
|
|
55
|
+ }
|
|
|
56
|
+
|
|
|
57
|
+ // 状态
|
|
|
58
|
+ if (filters.get("status") != null && !filters.get("status").toString().isEmpty()) {
|
|
|
59
|
+ sql.append(" AND b.status = ?");
|
|
|
60
|
+ params.add(filters.get("status"));
|
|
|
61
|
+ }
|
|
|
62
|
+
|
|
|
63
|
+ // 金额范围
|
|
|
64
|
+ if (filters.get("minAmount") != null) {
|
|
|
65
|
+ sql.append(" AND b.total_fee >= ?");
|
|
|
66
|
+ params.add(new BigDecimal(filters.get("minAmount").toString()));
|
|
|
67
|
+ }
|
|
|
68
|
+ if (filters.get("maxAmount") != null) {
|
|
|
69
|
+ sql.append(" AND b.total_fee <= ?");
|
|
|
70
|
+ params.add(new BigDecimal(filters.get("maxAmount").toString()));
|
|
|
71
|
+ }
|
|
|
72
|
+
|
|
|
73
|
+ sql.append(" ORDER BY b.created_at DESC");
|
|
|
74
|
+
|
|
|
75
|
+ // 分页
|
|
|
76
|
+ int page = filters.get("page") != null ? Integer.parseInt(filters.get("page").toString()) : 1;
|
|
|
77
|
+ int size = filters.get("size") != null ? Integer.parseInt(filters.get("size").toString()) : 20;
|
|
|
78
|
+ int offset = (page - 1) * size;
|
|
|
79
|
+
|
|
|
80
|
+ sql.append(" LIMIT ? OFFSET ?");
|
|
|
81
|
+ params.add(size);
|
|
|
82
|
+ params.add(offset);
|
|
|
83
|
+
|
|
|
84
|
+ List<Map<String, Object>> bills = jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
|
|
85
|
+
|
|
|
86
|
+ // 统计总数
|
|
|
87
|
+ String countSql = sql.toString().replaceFirst("SELECT .*? FROM", "SELECT COUNT(*) FROM")
|
|
|
88
|
+ .replaceAll(" ORDER BY.*", "");
|
|
|
89
|
+ Integer total = jdbcTemplate.queryForObject(countSql, Integer.class,
|
|
|
90
|
+ params.subList(0, params.size() - 2).toArray());
|
|
|
91
|
+
|
|
|
92
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
93
|
+ result.put("records", bills);
|
|
|
94
|
+ result.put("total", total);
|
|
|
95
|
+ result.put("page", page);
|
|
|
96
|
+ result.put("size", size);
|
|
|
97
|
+ result.put("pages", (total + size - 1) / size);
|
|
|
98
|
+
|
|
|
99
|
+ log.info("Bills queried: {} records, total: {}", bills.size(), total);
|
|
|
100
|
+ return result;
|
|
|
101
|
+ }
|
|
|
102
|
+
|
|
|
103
|
+ /**
|
|
|
104
|
+ * 多维度缴费查询
|
|
|
105
|
+ */
|
|
|
106
|
+ public Map<String, Object> queryPayments(Map<String, Object> filters) {
|
|
|
107
|
+ log.info("Querying payments with filters: {}", filters);
|
|
|
108
|
+
|
|
|
109
|
+ StringBuilder sql = new StringBuilder(
|
|
|
110
|
+ "SELECT p.*, b.bill_no, b.total_fee, c.customer_name, c.customer_no, c.area " +
|
|
|
111
|
+ "FROM rev_payment p " +
|
|
|
112
|
+ "JOIN rev_bill b ON p.bill_id = b.id " +
|
|
|
113
|
+ "JOIN rev_customer c ON p.customer_id = c.id " +
|
|
|
114
|
+ "WHERE 1=1");
|
|
|
115
|
+
|
|
|
116
|
+ List<Object> params = new ArrayList<>();
|
|
|
117
|
+
|
|
|
118
|
+ // 时间范围
|
|
|
119
|
+ if (filters.get("startDate") != null) {
|
|
|
120
|
+ sql.append(" AND p.paid_at >= ?::timestamp");
|
|
|
121
|
+ params.add(filters.get("startDate"));
|
|
|
122
|
+ }
|
|
|
123
|
+ if (filters.get("endDate") != null) {
|
|
|
124
|
+ sql.append(" AND p.paid_at <= ?::timestamp");
|
|
|
125
|
+ params.add(filters.get("endDate"));
|
|
|
126
|
+ }
|
|
|
127
|
+
|
|
|
128
|
+ // 区域
|
|
|
129
|
+ if (filters.get("area") != null && !filters.get("area").toString().isEmpty()) {
|
|
|
130
|
+ sql.append(" AND c.area = ?");
|
|
|
131
|
+ params.add(filters.get("area"));
|
|
|
132
|
+ }
|
|
|
133
|
+
|
|
|
134
|
+ // 支付方式
|
|
|
135
|
+ if (filters.get("payMethod") != null && !filters.get("payMethod").toString().isEmpty()) {
|
|
|
136
|
+ sql.append(" AND p.pay_method = ?");
|
|
|
137
|
+ params.add(filters.get("payMethod"));
|
|
|
138
|
+ }
|
|
|
139
|
+
|
|
|
140
|
+ // 支付渠道
|
|
|
141
|
+ if (filters.get("payChannel") != null && !filters.get("payChannel").toString().isEmpty()) {
|
|
|
142
|
+ sql.append(" AND p.pay_channel = ?");
|
|
|
143
|
+ params.add(filters.get("payChannel"));
|
|
|
144
|
+ }
|
|
|
145
|
+
|
|
|
146
|
+ // 金额范围
|
|
|
147
|
+ if (filters.get("minAmount") != null) {
|
|
|
148
|
+ sql.append(" AND p.amount >= ?");
|
|
|
149
|
+ params.add(new BigDecimal(filters.get("minAmount").toString()));
|
|
|
150
|
+ }
|
|
|
151
|
+ if (filters.get("maxAmount") != null) {
|
|
|
152
|
+ sql.append(" AND p.amount <= ?");
|
|
|
153
|
+ params.add(new BigDecimal(filters.get("maxAmount").toString()));
|
|
|
154
|
+ }
|
|
|
155
|
+
|
|
|
156
|
+ sql.append(" ORDER BY p.paid_at DESC");
|
|
|
157
|
+
|
|
|
158
|
+ // 分页
|
|
|
159
|
+ int page = filters.get("page") != null ? Integer.parseInt(filters.get("page").toString()) : 1;
|
|
|
160
|
+ int size = filters.get("size") != null ? Integer.parseInt(filters.get("size").toString()) : 20;
|
|
|
161
|
+ int offset = (page - 1) * size;
|
|
|
162
|
+
|
|
|
163
|
+ sql.append(" LIMIT ? OFFSET ?");
|
|
|
164
|
+ params.add(size);
|
|
|
165
|
+ params.add(offset);
|
|
|
166
|
+
|
|
|
167
|
+ List<Map<String, Object>> payments = jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
|
|
168
|
+
|
|
|
169
|
+ // 统计总数
|
|
|
170
|
+ String countSql = sql.toString().replaceFirst("SELECT .*? FROM", "SELECT COUNT(*) FROM")
|
|
|
171
|
+ .replaceAll(" ORDER BY.*", "");
|
|
|
172
|
+ Integer total = jdbcTemplate.queryForObject(countSql, Integer.class,
|
|
|
173
|
+ params.subList(0, params.size() - 2).toArray());
|
|
|
174
|
+
|
|
|
175
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
176
|
+ result.put("records", payments);
|
|
|
177
|
+ result.put("total", total);
|
|
|
178
|
+ result.put("page", page);
|
|
|
179
|
+ result.put("size", size);
|
|
|
180
|
+ result.put("pages", (total + size - 1) / size);
|
|
|
181
|
+
|
|
|
182
|
+ log.info("Payments queried: {} records, total: {}", payments.size(), total);
|
|
|
183
|
+ return result;
|
|
|
184
|
+ }
|
|
|
185
|
+
|
|
|
186
|
+ /**
|
|
|
187
|
+ * 月度营收报表
|
|
|
188
|
+ */
|
|
|
189
|
+ public Map<String, Object> monthlyReport(int year, int month) {
|
|
|
190
|
+ log.info("Generating monthly report: {}-{}", year, month);
|
|
|
191
|
+
|
|
|
192
|
+ String period = String.format("%04d-%02d", year, month);
|
|
|
193
|
+
|
|
|
194
|
+ Map<String, Object> report = new HashMap<>();
|
|
|
195
|
+ report.put("year", year);
|
|
|
196
|
+ report.put("month", month);
|
|
|
197
|
+ report.put("period", period);
|
|
|
198
|
+
|
|
|
199
|
+ // 账单统计
|
|
|
200
|
+ Map<String, Object> billStats = jdbcTemplate.queryForMap(
|
|
|
201
|
+ "SELECT COUNT(*) as billCount, " +
|
|
|
202
|
+ "COALESCE(SUM(total_fee), 0) as totalAmount, " +
|
|
|
203
|
+ "COALESCE(SUM(paid_fee), 0) as paidAmount, " +
|
|
|
204
|
+ "COALESCE(SUM(total_fee - paid_fee), 0) as unpaidAmount " +
|
|
|
205
|
+ "FROM rev_bill WHERE bill_period = ?",
|
|
|
206
|
+ period);
|
|
|
207
|
+ report.putAll(billStats);
|
|
|
208
|
+
|
|
|
209
|
+ // 缴费统计
|
|
|
210
|
+ Map<String, Object> paymentStats = jdbcTemplate.queryForMap(
|
|
|
211
|
+ "SELECT COUNT(*) as paymentCount, " +
|
|
|
212
|
+ "COALESCE(SUM(amount), 0) as paymentAmount " +
|
|
|
213
|
+ "FROM rev_payment p " +
|
|
|
214
|
+ "JOIN rev_bill b ON p.bill_id = b.id " +
|
|
|
215
|
+ "WHERE b.bill_period = ?",
|
|
|
216
|
+ period);
|
|
|
217
|
+ report.putAll(paymentStats);
|
|
|
218
|
+
|
|
|
219
|
+ // 按区域统计
|
|
|
220
|
+ List<Map<String, Object>> areaStats = jdbcTemplate.queryForList(
|
|
|
221
|
+ "SELECT c.area, COUNT(b.id) as billCount, " +
|
|
|
222
|
+ "COALESCE(SUM(b.total_fee), 0) as totalAmount, " +
|
|
|
223
|
+ "COALESCE(SUM(b.paid_fee), 0) as paidAmount " +
|
|
|
224
|
+ "FROM rev_bill b " +
|
|
|
225
|
+ "JOIN rev_customer c ON b.customer_id = c.id " +
|
|
|
226
|
+ "WHERE b.bill_period = ? " +
|
|
|
227
|
+ "GROUP BY c.area " +
|
|
|
228
|
+ "ORDER BY totalAmount DESC",
|
|
|
229
|
+ period);
|
|
|
230
|
+ report.put("areaStats", areaStats);
|
|
|
231
|
+
|
|
|
232
|
+ // 按支付方式统计
|
|
|
233
|
+ List<Map<String, Object>> paymentMethodStats = jdbcTemplate.queryForList(
|
|
|
234
|
+ "SELECT p.pay_method, COUNT(*) as count, " +
|
|
|
235
|
+ "COALESCE(SUM(p.amount), 0) as amount " +
|
|
|
236
|
+ "FROM rev_payment p " +
|
|
|
237
|
+ "JOIN rev_bill b ON p.bill_id = b.id " +
|
|
|
238
|
+ "WHERE b.bill_period = ? " +
|
|
|
239
|
+ "GROUP BY p.pay_method " +
|
|
|
240
|
+ "ORDER BY amount DESC",
|
|
|
241
|
+ period);
|
|
|
242
|
+ report.put("paymentMethodStats", paymentMethodStats);
|
|
|
243
|
+
|
|
|
244
|
+ log.info("Monthly report generated for {}: totalAmount={}, paidAmount={}",
|
|
|
245
|
+ period, billStats.get("totalAmount"), billStats.get("paidAmount"));
|
|
|
246
|
+ return report;
|
|
|
247
|
+ }
|
|
|
248
|
+
|
|
|
249
|
+ /**
|
|
|
250
|
+ * 年度营收报表
|
|
|
251
|
+ */
|
|
|
252
|
+ public Map<String, Object> yearlyReport(int year) {
|
|
|
253
|
+ log.info("Generating yearly report: {}", year);
|
|
|
254
|
+
|
|
|
255
|
+ Map<String, Object> report = new HashMap<>();
|
|
|
256
|
+ report.put("year", year);
|
|
|
257
|
+
|
|
|
258
|
+ // 年度总计
|
|
|
259
|
+ Map<String, Object> yearlyStats = jdbcTemplate.queryForMap(
|
|
|
260
|
+ "SELECT COUNT(*) as billCount, " +
|
|
|
261
|
+ "COALESCE(SUM(total_fee), 0) as totalAmount, " +
|
|
|
262
|
+ "COALESCE(SUM(paid_fee), 0) as paidAmount, " +
|
|
|
263
|
+ "COALESCE(SUM(total_fee - paid_fee), 0) as unpaidAmount " +
|
|
|
264
|
+ "FROM rev_bill WHERE EXTRACT(YEAR FROM created_at) = ?",
|
|
|
265
|
+ year);
|
|
|
266
|
+ report.putAll(yearlyStats);
|
|
|
267
|
+
|
|
|
268
|
+ // 年度缴费统计
|
|
|
269
|
+ Map<String, Object> paymentStats = jdbcTemplate.queryForMap(
|
|
|
270
|
+ "SELECT COUNT(*) as paymentCount, " +
|
|
|
271
|
+ "COALESCE(SUM(p.amount), 0) as paymentAmount " +
|
|
|
272
|
+ "FROM rev_payment p " +
|
|
|
273
|
+ "JOIN rev_bill b ON p.bill_id = b.id " +
|
|
|
274
|
+ "WHERE EXTRACT(YEAR FROM b.created_at) = ?",
|
|
|
275
|
+ year);
|
|
|
276
|
+ report.putAll(paymentStats);
|
|
|
277
|
+
|
|
|
278
|
+ // 按月统计
|
|
|
279
|
+ List<Map<String, Object>> monthlyStats = jdbcTemplate.queryForList(
|
|
|
280
|
+ "SELECT bill_period as month, COUNT(*) as billCount, " +
|
|
|
281
|
+ "COALESCE(SUM(total_fee), 0) as totalAmount, " +
|
|
|
282
|
+ "COALESCE(SUM(paid_fee), 0) as paidAmount " +
|
|
|
283
|
+ "FROM rev_bill " +
|
|
|
284
|
+ "WHERE EXTRACT(YEAR FROM created_at) = ? " +
|
|
|
285
|
+ "GROUP BY bill_period " +
|
|
|
286
|
+ "ORDER BY bill_period",
|
|
|
287
|
+ year);
|
|
|
288
|
+ report.put("monthlyStats", monthlyStats);
|
|
|
289
|
+
|
|
|
290
|
+ // 按区域统计
|
|
|
291
|
+ List<Map<String, Object>> areaStats = jdbcTemplate.queryForList(
|
|
|
292
|
+ "SELECT c.area, COUNT(b.id) as billCount, " +
|
|
|
293
|
+ "COALESCE(SUM(b.total_fee), 0) as totalAmount, " +
|
|
|
294
|
+ "COALESCE(SUM(b.paid_fee), 0) as paidAmount " +
|
|
|
295
|
+ "FROM rev_bill b " +
|
|
|
296
|
+ "JOIN rev_customer c ON b.customer_id = c.id " +
|
|
|
297
|
+ "WHERE EXTRACT(YEAR FROM b.created_at) = ? " +
|
|
|
298
|
+ "GROUP BY c.area " +
|
|
|
299
|
+ "ORDER BY totalAmount DESC",
|
|
|
300
|
+ year);
|
|
|
301
|
+ report.put("areaStats", areaStats);
|
|
|
302
|
+
|
|
|
303
|
+ log.info("Yearly report generated for {}: totalAmount={}, paidAmount={}",
|
|
|
304
|
+ year, yearlyStats.get("totalAmount"), yearlyStats.get("paidAmount"));
|
|
|
305
|
+ return report;
|
|
|
306
|
+ }
|
|
|
307
|
+
|
|
|
308
|
+ /**
|
|
|
309
|
+ * 导出账单(CSV 格式)
|
|
|
310
|
+ */
|
|
|
311
|
+ public String exportBills(Map<String, Object> filters) {
|
|
|
312
|
+ log.info("Exporting bills with filters: {}", filters);
|
|
|
313
|
+
|
|
|
314
|
+ StringBuilder sql = new StringBuilder(
|
|
|
315
|
+ "SELECT b.bill_no, c.customer_name, c.customer_no, c.area, c.customer_type, " +
|
|
|
316
|
+ "m.meter_no, b.bill_period, b.consumption, b.water_fee, b.sewage_fee, " +
|
|
|
317
|
+ "b.total_fee, b.paid_fee, b.status, b.due_date, b.created_at " +
|
|
|
318
|
+ "FROM rev_bill b " +
|
|
|
319
|
+ "JOIN rev_customer c ON b.customer_id = c.id " +
|
|
|
320
|
+ "JOIN rev_meter m ON b.meter_id = m.id " +
|
|
|
321
|
+ "WHERE 1=1");
|
|
|
322
|
+
|
|
|
323
|
+ List<Object> params = new ArrayList<>();
|
|
|
324
|
+
|
|
|
325
|
+ // 应用过滤条件(同 queryBills)
|
|
|
326
|
+ if (filters.get("startDate") != null) {
|
|
|
327
|
+ sql.append(" AND b.created_at >= ?::timestamp");
|
|
|
328
|
+ params.add(filters.get("startDate"));
|
|
|
329
|
+ }
|
|
|
330
|
+ if (filters.get("endDate") != null) {
|
|
|
331
|
+ sql.append(" AND b.created_at <= ?::timestamp");
|
|
|
332
|
+ params.add(filters.get("endDate"));
|
|
|
333
|
+ }
|
|
|
334
|
+ if (filters.get("area") != null && !filters.get("area").toString().isEmpty()) {
|
|
|
335
|
+ sql.append(" AND c.area = ?");
|
|
|
336
|
+ params.add(filters.get("area"));
|
|
|
337
|
+ }
|
|
|
338
|
+ if (filters.get("customerType") != null && !filters.get("customerType").toString().isEmpty()) {
|
|
|
339
|
+ sql.append(" AND c.customer_type = ?");
|
|
|
340
|
+ params.add(filters.get("customerType"));
|
|
|
341
|
+ }
|
|
|
342
|
+ if (filters.get("status") != null && !filters.get("status").toString().isEmpty()) {
|
|
|
343
|
+ sql.append(" AND b.status = ?");
|
|
|
344
|
+ params.add(filters.get("status"));
|
|
|
345
|
+ }
|
|
|
346
|
+
|
|
|
347
|
+ sql.append(" ORDER BY b.created_at DESC LIMIT 10000"); // 限制导出数量
|
|
|
348
|
+
|
|
|
349
|
+ List<Map<String, Object>> bills = jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
|
|
350
|
+
|
|
|
351
|
+ // 生成 CSV
|
|
|
352
|
+ StringBuilder csv = new StringBuilder();
|
|
|
353
|
+ csv.append("账单编号,客户名称,客户编号,区域,客户类型,水表号,账期,用水量,水费,污水处理费,")
|
|
|
354
|
+ .append("总金额,已缴金额,状态,到期日期,创建时间\n");
|
|
|
355
|
+
|
|
|
356
|
+ for (Map<String, Object> bill : bills) {
|
|
|
357
|
+ csv.append(escapeCsv(bill.get("bill_no"))).append(",")
|
|
|
358
|
+ .append(escapeCsv(bill.get("customer_name"))).append(",")
|
|
|
359
|
+ .append(escapeCsv(bill.get("customer_no"))).append(",")
|
|
|
360
|
+ .append(escapeCsv(bill.get("area"))).append(",")
|
|
|
361
|
+ .append(escapeCsv(bill.get("customer_type"))).append(",")
|
|
|
362
|
+ .append(escapeCsv(bill.get("meter_no"))).append(",")
|
|
|
363
|
+ .append(escapeCsv(bill.get("bill_period"))).append(",")
|
|
|
364
|
+ .append(bill.get("consumption")).append(",")
|
|
|
365
|
+ .append(bill.get("water_fee")).append(",")
|
|
|
366
|
+ .append(bill.get("sewage_fee")).append(",")
|
|
|
367
|
+ .append(bill.get("total_fee")).append(",")
|
|
|
368
|
+ .append(bill.get("paid_fee")).append(",")
|
|
|
369
|
+ .append(escapeCsv(bill.get("status"))).append(",")
|
|
|
370
|
+ .append(bill.get("due_date")).append(",")
|
|
|
371
|
+ .append(bill.get("created_at")).append("\n");
|
|
|
372
|
+ }
|
|
|
373
|
+
|
|
|
374
|
+ log.info("Bills exported: {} records", bills.size());
|
|
|
375
|
+ return csv.toString();
|
|
|
376
|
+ }
|
|
|
377
|
+
|
|
|
378
|
+ /**
|
|
|
379
|
+ * CSV 字段转义
|
|
|
380
|
+ */
|
|
|
381
|
+ private String escapeCsv(Object value) {
|
|
|
382
|
+ if (value == null) {
|
|
|
383
|
+ return "";
|
|
|
384
|
+ }
|
|
|
385
|
+ String str = value.toString();
|
|
|
386
|
+ if (str.contains(",") || str.contains("\"") || str.contains("\n")) {
|
|
|
387
|
+ return "\"" + str.replace("\"", "\"\"") + "\"";
|
|
|
388
|
+ }
|
|
|
389
|
+ return str;
|
|
|
390
|
+ }
|
|
|
391
|
+}
|