You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1063 lines
51 KiB

7 months ago
2 months ago
5 months ago
7 months ago
2 months ago
7 months ago
7 months ago
5 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
5 months ago
2 months ago
7 months ago
5 months ago
7 months ago
5 months ago
7 months ago
5 months ago
7 months ago
5 months ago
5 months ago
5 months ago
7 months ago
5 months ago
2 months ago
2 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
1 month ago
7 months ago
  1. package com.example.demo.serviceImpl.cash;
  2. import com.example.demo.Util.LanguageTranslationUtil;
  3. import com.example.demo.Util.SimpleIdGenerator;
  4. import com.example.demo.domain.entity.*;
  5. import com.example.demo.Util.BusinessException;
  6. import com.example.demo.Util.GoldTistV2;
  7. import com.example.demo.config.RabbitMQConfig;
  8. import com.example.demo.domain.vo.bean.Region;
  9. import com.example.demo.domain.vo.cash.*;
  10. import com.example.demo.domain.vo.coin.Messages;
  11. import com.example.demo.domain.vo.coin.Result;
  12. import com.example.demo.exception.SystemException;
  13. import com.example.demo.mapper.cash.CashCollectionMapper;
  14. import com.example.demo.mapper.cash.CashRefundMapper;
  15. import com.example.demo.mapper.coin.*;
  16. import com.example.demo.service.Wallet.WalletService;
  17. import com.example.demo.service.cash.RefundService;
  18. import com.example.demo.service.coin.TranslationService;
  19. import com.github.pagehelper.PageHelper;
  20. import com.github.pagehelper.PageInfo;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.apache.commons.collections4.CollectionUtils;
  23. import org.springframework.amqp.rabbit.core.RabbitTemplate;
  24. import org.springframework.beans.factory.annotation.Autowired;
  25. import org.springframework.stereotype.Service;
  26. import org.springframework.transaction.annotation.Transactional;
  27. import org.springframework.web.bind.annotation.RequestHeader;
  28. import com.example.demo.domain.DTO.Currency;
  29. import java.math.BigDecimal;
  30. import java.math.RoundingMode;
  31. import java.time.LocalDate;
  32. import java.util.*;
  33. import java.util.function.Function;
  34. import java.util.stream.Collectors;
  35. import static org.apache.commons.lang3.StringUtils.substring;
  36. /**
  37. * @program: GOLD
  38. * @ClassName CashRefundServiceImpl
  39. * @description:
  40. * @author: huangqizhen
  41. * @create: 202509-28 15:02
  42. * @Version 1.0
  43. **/
  44. @Service
  45. @Slf4j
  46. public class CashRefundServiceImpl implements RefundService {
  47. @Autowired
  48. private CashRefundMapper cashRefundMapper;
  49. @Autowired
  50. private RefundMapper refundMapper;
  51. @Autowired
  52. private AuditMapper auditMapper;
  53. @Autowired
  54. private MarketMapper marketMapper;
  55. @Autowired
  56. private RabbitTemplate rabbitTemplate;
  57. @Autowired
  58. private OperationLogMapper operationLogMapper;
  59. @Autowired
  60. private CashCollectionMapper cashCollectionMapper;
  61. @Autowired
  62. private LanguageTranslationUtil languageTranslationUtil;
  63. @Autowired
  64. private WalletService walletService;
  65. @Autowired
  66. private TranslationService translationService;
  67. @Autowired
  68. private WalletMapper walletMapper;
  69. @Autowired
  70. private UserMapper userMapper;
  71. @Override
  72. public PageInfo<CashRecordDTO> select(Integer pageNum, Integer pageSize, CashRecordDTO cashRecordDTO) {
  73. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  74. List<CashRecordDTO> list = cashRefundMapper.select(cashRecordDTO);
  75. if (list.isEmpty()) {
  76. return new PageInfo<>(list);
  77. }
  78. // 批量收集ID
  79. Set<Integer> relatedIds = new HashSet<>();
  80. Set<Integer> marketIds = new HashSet<>();
  81. Set<Integer> submitterIds = new HashSet<>();
  82. Set<Integer> auditIds = new HashSet<>();
  83. Set<Integer> executorIds = new HashSet<>();
  84. list.forEach(item -> {
  85. if (item.getRelatedId() != null) relatedIds.add(item.getRelatedId());
  86. if (item.getMarket() != null) marketIds.add(item.getMarket());
  87. if (item.getSubmitterId() != null) submitterIds.add(item.getSubmitterId());
  88. if (item.getAuditId() != null) auditIds.add(item.getAuditId());
  89. if (item.getExecutor() != null) executorIds.add(item.getExecutor());
  90. });
  91. // 批量查询
  92. Map<Integer, CashCollection> cashCollectionMap = cashCollectionMapper.selectBatchIds(relatedIds)
  93. .stream().collect(Collectors.toMap(CashCollection::getId, Function.identity()));
  94. Map<Integer, String> marketNameMap = marketMapper.getMarketByIds(marketIds)
  95. .stream().collect(Collectors.toMap(Market::getId, Market::getName));
  96. Map<Integer, String> submitterNameMap = auditMapper.getNamesByIds(submitterIds)
  97. .stream().collect(Collectors.toMap(Admin::getId, Admin::getAdminName));
  98. Map<Integer, LhlAudit> auditMap = cashRefundMapper.getAuditBatch(auditIds)
  99. .stream().collect(Collectors.toMap(LhlAudit::getId, Function.identity()));
  100. Map<String, String> executorNameMap = auditMapper.getNamesByJwcodes(executorIds)
  101. .stream().collect(Collectors.toMap(Admin::getAccount, Admin::getAdminName));
  102. // 处理数据
  103. list.forEach(item -> {
  104. CashCollection cashCollection = cashCollectionMap.get(item.getRelatedId());
  105. if (cashCollection != null) {
  106. processCashCollection(item, cashCollection);
  107. }
  108. String marketName = marketNameMap.get(item.getMarket());
  109. String submitter = submitterNameMap.get(item.getSubmitterId());
  110. LhlAudit lhlAudit = auditMap.get(item.getAuditId());
  111. String executorName = executorNameMap.get(String.valueOf(item.getExecutor()));
  112. item.setMarketName(marketName != null ? marketName : "");
  113. item.setSubmitter(submitter != null ? submitter : "");
  114. item.setExecutorName(executorName != null ? executorName : "");
  115. if (lhlAudit != null) {
  116. item.setAreaServise(lhlAudit.getAreaServise());
  117. item.setAreaFinance(lhlAudit.getAreaFinance());
  118. item.setAreaCharge(lhlAudit.getAreaCharge());
  119. item.setHeadFinance(lhlAudit.getHeadFinance());
  120. }
  121. });
  122. return new PageInfo<>(list);
  123. }
  124. private void processCashCollection(CashRecordDTO item, CashCollection cashCollection) {
  125. // 设置默认值
  126. Integer freeGold = cashCollection.getFreeGold() != null ? cashCollection.getFreeGold() : 0;
  127. Integer permanentGold = cashCollection.getPermanentGold() != null ? cashCollection.getPermanentGold() : 0;
  128. BigDecimal free = new BigDecimal(freeGold).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
  129. BigDecimal permanent = new BigDecimal(permanentGold).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
  130. item.setGold(permanent);
  131. item.setFree(free);
  132. item.setActivity(cashCollection.getActivity());
  133. item.setPaymentCurrency(cashCollection.getPaymentCurrency());
  134. if (cashCollection.getPaymentCurrency() != null) {
  135. item.setPaymentAmount(cashCollection.getPaymentAmount().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
  136. } else item.setPaymentAmount(cashCollection.getPaymentAmount());
  137. item.setReceivedCurrency(cashCollection.getReceivedCurrency());
  138. if (cashCollection.getReceivedCurrency() != null) {
  139. item.setReceivedAmount(cashCollection.getReceivedAmount().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
  140. } else item.setReceivedAmount(cashCollection.getReceivedAmount());
  141. item.setPayType(cashCollection.getPayType());
  142. item.setPayTime(cashCollection.getPayTime());
  143. item.setPayBankCode(cashCollection.getBankCode());
  144. item.setPaySubmitter(cashCollection.getSubmitterName());
  145. item.setAudit(cashCollection.getAuditName());
  146. item.setReceivedTime(cashCollection.getReceivedTime());
  147. item.setPayVoucher(cashCollection.getVoucher());
  148. item.setPayRemark(cashCollection.getRemark());
  149. item.setHandlingCharge(cashCollection.getHandlingCharge().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
  150. // 处理金币金额
  151. if (item.getPermanentGold() != null) {
  152. item.setPermanentGold(item.getPermanentGold().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
  153. }
  154. if (item.getFreeGold() != null) {
  155. item.setFreeGold(item.getFreeGold().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
  156. }
  157. }
  158. @Override
  159. public int add(CashRecordRefund cashRecordRefund, @RequestHeader(defaultValue = "zh_CN") String lang) throws Exception {
  160. try {
  161. if (cashRecordRefund.getJwcode() == null) {
  162. throw new Exception("未输入精网号");
  163. }
  164. if (cashRecordRefund.getRefundModel() == null) {
  165. throw new Exception("请填充退款类型");
  166. }
  167. if (cashRecordRefund.getRefundReason() == null) {
  168. throw new Exception("请填写退款理由");
  169. }
  170. if (cashRecordRefund.getHandlingCharge() == null) {
  171. throw new Exception("请先填写手续费");
  172. }
  173. if (cashRecordRefund.getMarket() == null || cashRecordRefund.getMarket().trim().isEmpty()) {
  174. throw new Exception("请选择所属地区");
  175. }
  176. if(cashRecordRefund.getWalletId() != null) {
  177. String payType = cashRecordRefund.getPayType();
  178. Integer wallet = null;
  179. if (payType == null || payType.trim().isEmpty()) {
  180. throw new SystemException("未穿输支付方式");
  181. }
  182. if (payType.equals("Stripe") || payType.equals("PaymentAsia")) {
  183. wallet = 2;
  184. }
  185. if (payType.equals("FirstData") || payType.equals("Grabpay") || payType.equals("Nets") || payType.equals("PayPal") || payType.equals("IOS")) {
  186. wallet = 5;
  187. }
  188. if (payType.equals("Stripe2")) {
  189. wallet = 3;
  190. }
  191. if (payType.equals("Ipay88")) {
  192. wallet = 4;
  193. }
  194. if (payType.equals("E-Transfer")) {
  195. wallet = 6;
  196. }
  197. if (payType.equals("paysolution")) {
  198. wallet = 8;
  199. }
  200. String payType1 = languageTranslationUtil.translate("银行转账", lang);
  201. String payType2 = languageTranslationUtil.translate("现金", lang);
  202. String payType3 = languageTranslationUtil.translate("支票", lang);
  203. String payType4 = languageTranslationUtil.translate("刷卡", lang);
  204. if (payType.equals(payType1) || payType.equals(payType2) || payType.equals(payType3) || payType.equals(payType4)) {
  205. wallet = cashRecordRefund.getWalletId();
  206. }
  207. UserRegionWallet userRegionWallet = walletMapper.selectWallet(cashRecordRefund.getJwcode(), wallet);
  208. User user = userMapper.selectUserByJwcode(cashRecordRefund.getJwcode());
  209. if (user.getCurrentFreeJune().add(user.getCurrentFreeDecember()).compareTo(BigDecimal.valueOf(cashRecordRefund.getPartRefundFree())) < 0) {
  210. String errorMsg = languageTranslationUtil.translate("用户钱包余额不足", lang);
  211. throw new BusinessException(errorMsg);
  212. }
  213. if (userRegionWallet == null) {
  214. //初始化钱包
  215. walletMapper.insert(new UserRegionWallet(null, cashRecordRefund.getJwcode(), wallet, BigDecimal.ZERO, new Date(), new Date()));
  216. log.warn("用户钱包不存在,已初始化钱包");
  217. }
  218. if (userRegionWallet.getCurrentPermanentGold().compareTo(BigDecimal.valueOf(cashRecordRefund.getPartRefundGold())) < 0) {
  219. throw new BusinessException("用户钱包金币不足");
  220. }
  221. }
  222. CashRecordDone cashRecordDonetwo = new CashRecordDone();
  223. cashRecordDonetwo.setAreaServise(cashRecordRefund.getAreaServise());
  224. cashRefundMapper.addAudit(cashRecordDonetwo);
  225. cashRecordRefund.setAuditId(cashRecordDonetwo.getId());
  226. cashRecordRefund.setStatus(10);
  227. //生成订单号后半部分
  228. String orderNumber = cashRecordRefund.getOrderCode();
  229. //构建订单信息
  230. cashRecordRefund.setOrderCode("TK" + orderNumber); //订单号
  231. // 查询市场 ID,增加空值检查和多语言支持
  232. String marketName = cashRecordRefund.getMarket();
  233. String marketId = marketMapper.getMarketId(marketName);
  234. // 如果直接查询失败,尝试将英文名称转换为中文后再次查询
  235. if (marketId == null || marketId.trim().isEmpty()) {
  236. String chineseMarketName = translationService.findChineseSimplifiedByTranslation(marketName, "en");
  237. if (chineseMarketName != null && !chineseMarketName.equals(marketName)) {
  238. marketId = marketMapper.getMarketId(chineseMarketName);
  239. }
  240. }
  241. if (marketId == null || marketId.trim().isEmpty()) {
  242. throw new Exception("无效的所属地区:" + cashRecordRefund.getMarket());
  243. }
  244. cashRecordRefund.setMarket(String.valueOf(Integer.valueOf(marketId)));
  245. cashRefundMapper.insert(cashRecordRefund);
  246. CashRecordDone cashRecordDone1 = new CashRecordDone();
  247. cashRecordDone1.setId(cashRecordRefund.getOriginalOrderId());
  248. cashRecordDone1.setStatus(6);
  249. if (cashRecordDone1.getId() != null || cashRecordDone1.getOrderCode() != null) {
  250. cashRefundMapper.updateStatus(cashRecordDone1);
  251. } else {
  252. return Result.error("提交失败").getCode();
  253. }
  254. // 发送退款创建消息
  255. Messages message = new Messages();
  256. message.setJwcode(cashRecordRefund.getJwcode());
  257. message.setName(cashRecordRefund.getName());
  258. message.setStatus(cashRecordRefund.getStatus());
  259. message.setDesc("的客服退款申请待审核,前往处理");
  260. message.setTitle("现金退款--新增退款");
  261. message.setType(0);
  262. message.setTypeId(cashRecordRefund.getId());
  263. message.setMarket(Integer.valueOf(cashRecordRefund.getMarket()));
  264. String marketName2 = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  265. message.setMarketName(marketName2);
  266. message.setQueryId(103);
  267. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
  268. return Result.success("提交成功").getCode();
  269. } catch (Exception e) {
  270. log.error("add error", e);
  271. throw e;
  272. }
  273. }
  274. @Override
  275. public int update(CashRecordDone cashRecordDone) throws Exception {
  276. if (cashRecordDone.getJwcode() == null) {
  277. throw new RuntimeException("未输入精网号");
  278. }
  279. if (cashRecordDone.getPaymentAmount() == null) {
  280. throw new RuntimeException("未输入付款金额");
  281. }
  282. if (cashRecordDone.getPaymentCurrency() == null) {
  283. throw new RuntimeException("未输入付款币种");
  284. }
  285. if (cashRecordDone.getRefundModel() == null) {
  286. throw new RuntimeException("请填写退款类型");
  287. }
  288. if (cashRecordDone.getRefundReason() == null) {
  289. throw new RuntimeException("请填写退款理由");
  290. }
  291. if (cashRecordDone.getNewRefundGold() == null) {
  292. cashRecordDone.setNewRefundGold(BigDecimal.valueOf(0));
  293. }
  294. if (cashRecordDone.getNewRefundFree() == null) {
  295. cashRecordDone.setNewRefundFree(BigDecimal.valueOf(0));
  296. }
  297. int result = cashRefundMapper.update(cashRecordDone);
  298. CashRecordDTO cashRecordDTO = cashRefundMapper.selectById(cashRecordDone.getId());
  299. if (result > 0) {
  300. // 发送审核消息
  301. Messages message = new Messages();
  302. message.setJwcode(cashRecordDTO.getJwcode());
  303. message.setName(cashRecordDTO.getName());
  304. message.setStatus(cashRecordDTO.getStatus());
  305. message.setDesc("的退款申请待审核,前往处理");
  306. message.setTitle("现金管理--退款审批");
  307. message.setType(1);
  308. message.setTypeId(cashRecordDTO.getId());
  309. message.setMarket(cashRecordDTO.getMarket());
  310. String marketName = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  311. message.setMarketName(marketName);
  312. message.setQueryId(103);
  313. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
  314. }
  315. return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
  316. }
  317. @Override
  318. public int withdraw(CashRecordDone cashRecordDone) {
  319. // 撤回订单
  320. int result = cashRefundMapper.withdraw(cashRecordDone.getId());
  321. if (result > 0) {
  322. // 更新与该订单关联的消息记录的flag字段为1
  323. cashRefundMapper.updateMessageFlagByOrderId(cashRecordDone.getId());
  324. }
  325. return result;
  326. }
  327. @Override
  328. public int review(CashRecordDone cashRecordDone, @RequestHeader(defaultValue = "zh_CN") String lang) throws Exception {
  329. if (cashRecordDone.getStatus() == 12 || cashRecordDone.getStatus() == 22) {
  330. if (cashRecordDone.getOrderCode() == null) {
  331. throw new RuntimeException("未输入订单号");
  332. }
  333. CashRecordDone cashRecordDone1 = new CashRecordDone();
  334. cashRecordDone1.setId(cashRecordDone.getRelatedId());
  335. cashRecordDone1.setOrderCode(cashRecordDone.getOrderCode().substring(2));
  336. cashRecordDone1.setStatus(4);
  337. if (cashRecordDone1.getId() != null || cashRecordDone1.getOrderCode() != null) {
  338. cashRefundMapper.updateStatus(cashRecordDone1);
  339. }
  340. }
  341. cashRefundMapper.updateAudit(cashRecordDone);
  342. int result = cashRefundMapper.review(cashRecordDone);
  343. CashRecordDTO cashRecordDTO = cashRefundMapper.selectById(cashRecordDone.getId());
  344. if (result > 0) {
  345. // 发送审核消息
  346. Messages message = new Messages();
  347. message.setJwcode(cashRecordDTO.getJwcode());
  348. message.setName(cashRecordDTO.getName());
  349. message.setStatus(cashRecordDTO.getStatus());
  350. if (cashRecordDTO.getStatus()==20) {
  351. message.setDesc("的现金退款申请待审批,前往处理");
  352. message.setTitle("现金管理--退款审批(负责人)");
  353. message.setQueryId(107);
  354. } else if (cashRecordDTO.getStatus()==30) {
  355. message.setDesc("的现金退款申请待审核,前往处理");
  356. message.setTitle("现金管理--退款审批(总部财务)");
  357. message.setQueryId(111);
  358. } else {
  359. message.setDesc("的现金退款申请已被驳回,前往查看详情");
  360. message.setTitle("现金管理--退款提交");
  361. message.setQueryId(99);
  362. }
  363. message.setType(1);
  364. message.setTypeId(cashRecordDTO.getId());
  365. message.setMarket(cashRecordDTO.getMarket());
  366. String marketName = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  367. message.setMarketName(marketName);
  368. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
  369. }
  370. return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
  371. }
  372. @Override
  373. public int executor(CashRecordDone cashRecordDone) throws Exception {
  374. if (cashRecordDone.getRefundVoucher() == null) {
  375. throw new RuntimeException("未输入退款凭证");
  376. }
  377. if (cashRecordDone.getRefundTime() == null) {
  378. throw new RuntimeException("未输入退款时间");
  379. }
  380. if (cashRecordDone.getRefundRemark() == null) {
  381. throw new RuntimeException("未输入退款备注");
  382. }
  383. if (cashRecordDone.getRefundChannels() == null) {
  384. throw new RuntimeException("未输入退款途径");
  385. }
  386. if (cashRecordDone.getRefundCurrency() == null) {
  387. throw new RuntimeException("未输入退款币种");
  388. }
  389. if (cashRecordDone.getRefundAmount() == null) {
  390. throw new RuntimeException("未输入退款金额");
  391. }
  392. int result = cashRefundMapper.executor(cashRecordDone);
  393. return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
  394. }
  395. @Override
  396. public int updateStatus(CashRecordDone cashRecordDone) {
  397. return cashRefundMapper.updateStatus(cashRecordDone);
  398. }
  399. @Transactional(rollbackFor = Exception.class)
  400. @Override
  401. public int finalreview(CashRecordDone cashRecordDone, @RequestHeader(defaultValue = "zh_CN") String lang) {
  402. if (cashRecordDone.getPermanentGold() == null) {
  403. cashRecordDone.setPermanentGold(0);
  404. }
  405. if (cashRecordDone.getFreeGold() == null) {
  406. cashRecordDone.setFreeGold(0);
  407. }
  408. if (cashRecordDone.getStatus() == 32) {
  409. CashRecordDone cashRecordDone1 = new CashRecordDone();
  410. cashRecordDone1.setOrderCode(cashRecordDone.getOrderCode().substring(2));
  411. cashRecordDone1.setStatus(4);
  412. if (cashRecordDone1.getId() != null || cashRecordDone1.getOrderCode() != null) {
  413. cashRefundMapper.updateStatus(cashRecordDone1);
  414. }
  415. }
  416. if (cashRecordDone.getGoodsName() != null && cashRecordDone.getStatus() == 40 &&
  417. (cashRecordDone.getGoodsName().equals(languageTranslationUtil.translate("金币充值", lang)) ||
  418. cashRecordDone.getGoodsName().contains(languageTranslationUtil.translate("金币充值", lang)))) {
  419. UserGoldRecord userGoldRecord = new UserGoldRecord();
  420. userGoldRecord.setOrderCode(cashRecordDone.getOrderCode());
  421. String orderCode = cashRecordDone.getOrderCode();
  422. if (orderCode != null && orderCode.length() > 4 && orderCode.startsWith("TKXJ")) {
  423. orderCode = "XJCZ" + orderCode.substring(4);
  424. }
  425. userGoldRecord.setType((byte) 2);
  426. userGoldRecord.setIsRefund((byte) 1);
  427. userGoldRecord.setRefundType("金币退款");
  428. if (cashRecordDone.getRefundModel() == 1) {
  429. userGoldRecord.setRefundModel(Byte.valueOf("1"));
  430. } else if (cashRecordDone.getRefundModel() == 0) {
  431. userGoldRecord.setRefundModel(Byte.valueOf("0"));
  432. }
  433. userGoldRecord.setJwcode(cashRecordDone.getJwcode());
  434. userGoldRecord.setSumGold(cashRecordDone.getPermanentGold() + cashRecordDone.getFreeGold());
  435. userGoldRecord.setPermanentGold(cashRecordDone.getPermanentGold());
  436. int currentMonth = LocalDate.now().getMonthValue();
  437. if (currentMonth >= 1 && currentMonth <= 6) {
  438. // 1-6月:设置12月额度,6月保持默认值
  439. userGoldRecord.setFreeJune(0);
  440. userGoldRecord.setFreeDecember(cashRecordDone.getFreeGold());
  441. } else {
  442. // 7-12月:设置6月额度,12月保持默认值
  443. userGoldRecord.setFreeJune(cashRecordDone.getFreeGold());
  444. userGoldRecord.setFreeDecember(0);
  445. }
  446. userGoldRecord.setGoodsName("金币充值");
  447. userGoldRecord.setPayPlatform("金币系统");
  448. userGoldRecord.setRemark(cashRecordDone.getRemark());
  449. userGoldRecord.setAdminId(cashRecordDone.getAdminId());
  450. userGoldRecord.setAuditStatus(1);
  451. userGoldRecord.setTaskGold(0);
  452. userGoldRecord.setCreateTime(new Date());
  453. userGoldRecord.setUpdateTime(new Date());
  454. String auditName = auditMapper.getName(cashRecordDone.getAuditId());
  455. refundMapper.add(userGoldRecord);
  456. cashRefundMapper.updategold(orderCode);
  457. User user = new User();
  458. user.setJwcode(userGoldRecord.getJwcode());
  459. user.setCurrentPermanentGold(BigDecimal.valueOf(-userGoldRecord.getPermanentGold())); //当前永久金币
  460. user.setCurrentFreeJune(BigDecimal.valueOf(-userGoldRecord.getFreeJune())); //当前六月免费金币
  461. user.setCurrentFreeDecember(BigDecimal.valueOf(-userGoldRecord.getFreeDecember())); //当前十二月免费金币
  462. auditMapper.updateUserGold(user);
  463. // 钱包更新 - 按原始充值流水 wallet_id 优先级顺序原路退回(1-10,越小优先级越高)
  464. String orderCodeA = "XJ" + orderCode.substring(4);
  465. // 1. 查询原始充值流水(type=0 充值,status=0 正常)
  466. List<UserWalletRecord> originalRecords = walletService.selectUserWalletRecord(userGoldRecord.getJwcode(), orderCodeA);
  467. if (!CollectionUtils.isEmpty(originalRecords)) {
  468. // 过滤充值记录并按 wallet_id 升序排序
  469. originalRecords = originalRecords.stream()
  470. .filter(r -> r.getType() == 0 && r.getStatus() == 0)
  471. .sorted(Comparator.comparing(UserWalletRecord::getWalletId))
  472. .collect(Collectors.toList());
  473. // 2. 本次退款总金额(取绝对值)
  474. BigDecimal totalRefundAmount = BigDecimal.valueOf(userGoldRecord.getPermanentGold()).abs();
  475. if (totalRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
  476. // 🔥【新增】预校验:检查用户余额是否足够退款
  477. BigDecimal userTotalBalance = getUserTotalBalance(userGoldRecord.getJwcode(), originalRecords);
  478. if (userTotalBalance.compareTo(totalRefundAmount) < 0) {
  479. // 🔥 余额不足,直接报错返回(根据项目规范选择抛异常或返回错误码)
  480. String errorMsg = String.format("退款失败:用户余额不足 | jwcode=%s, 待退金额=%s, 当前余额=%s",
  481. userGoldRecord.getJwcode(), totalRefundAmount, userTotalBalance);
  482. log.error(errorMsg);
  483. throw new BusinessException("WALLET_REFUND_INSUFFICIENT"+ errorMsg);
  484. // 或者:return Result.fail("WALLET_REFUND_INSUFFICIENT", "余额不足,无法退款");
  485. }
  486. BigDecimal remainingRefund = totalRefundAmount;
  487. // 3. 按原始流水顺序退回(支持多钱包)
  488. for (UserWalletRecord record : originalRecords) {
  489. if (remainingRefund.compareTo(BigDecimal.ZERO) <= 0) {
  490. break;
  491. }
  492. Integer walletId = record.getWalletId();
  493. BigDecimal originalAmount = BigDecimal.valueOf(record.getAmount()).abs();
  494. if (originalAmount.compareTo(BigDecimal.ZERO) <= 0) {
  495. continue;
  496. }
  497. // 4. 计算本次退回金额
  498. BigDecimal refundAmount = originalAmount.min(remainingRefund);
  499. if (refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
  500. continue;
  501. }
  502. // 5. 插入退款流水(amount 存负数,表示扣减)
  503. UserWalletRecord refundRecord = new UserWalletRecord();
  504. refundRecord.setType(2); // 充值退款类型
  505. refundRecord.setJwcode(userGoldRecord.getJwcode());
  506. refundRecord.setWalletId(walletId);
  507. refundRecord.setAmount(refundAmount.negate().intValue()); // 🔥 负数扣款
  508. refundRecord.setOrderCode("TK" + orderCodeA);
  509. if (cashRecordDone.getRefundModel()==1) {
  510. refundRecord.setDescription("部分退款");
  511. }
  512. else if (cashRecordDone.getRefundModel()==0) {
  513. refundRecord.setDescription("全部退款");
  514. }
  515. refundRecord.setStatus(0);
  516. walletService.addUserWalletRecord(refundRecord);
  517. // 6. 查询并更新钱包余额
  518. UserRegionWallet currentWallet = walletMapper.selectWallet(userGoldRecord.getJwcode(), walletId);
  519. if (currentWallet == null) {
  520. log.error("钱包记录不存在,无法退款 | jwcode={}, walletId={}", userGoldRecord.getJwcode(), walletId);
  521. continue;
  522. }
  523. // 7. 扣减余额
  524. BigDecimal newBalance = currentWallet.getCurrentPermanentGold().subtract(refundAmount);
  525. // 🔥 兜底:理论上预校验已通过,这里不会再出现负数,但保留防御式编程
  526. if (newBalance.compareTo(BigDecimal.ZERO) < 0) {
  527. log.warn("退款后余额为负,强制置零 | jwcode={}, walletId={}", userGoldRecord.getJwcode(), walletId);
  528. newBalance = BigDecimal.ZERO;
  529. }
  530. currentWallet.setCurrentPermanentGold(newBalance);
  531. walletMapper.updateWallet(currentWallet);
  532. // 8. 更新原流水状态
  533. walletService.updateUserWalletRecord(record.getId());
  534. // 9. 扣减剩余待退金额
  535. remainingRefund = remainingRefund.subtract(refundAmount);
  536. }
  537. }
  538. }
  539. GoldTistV2.addCoinNew(userGoldRecord.getJwcode().toString(), 58, //退款免费+永久金币-充值
  540. (double) (userGoldRecord.getFreeDecember() + userGoldRecord.getFreeJune() + userGoldRecord.getPermanentGold()) / 100, SimpleIdGenerator.generateId(),
  541. userGoldRecord.getRemark(), (double) userGoldRecord.getPermanentGold() / 100, auditName, "退款金币充值");
  542. }
  543. cashRefundMapper.updateAudit(cashRecordDone);
  544. int result = cashRefundMapper.review(cashRecordDone);
  545. CashRecordDTO cashRecordDTO = cashRefundMapper.selectById(cashRecordDone.getId());
  546. if (result > 0) {
  547. // 发送审核消息
  548. Messages message = new Messages();
  549. message.setJwcode(cashRecordDTO.getJwcode());
  550. message.setName(cashRecordDTO.getName());
  551. message.setStatus(cashRecordDTO.getStatus());
  552. message.setDesc(cashRecordDTO.getStatus() != 32 ? "的退款记录需填写执行明细,前往查看处理" : "的现金退款申请已被驳回,前往查看详情");
  553. message.setTitle(cashRecordDTO.getStatus() != 32 ? "现金管理--执行明细填写":"现金管理--退款提交");
  554. message.setType(1);
  555. message.setTypeId(cashRecordDTO.getId());
  556. message.setMarket(cashRecordDTO.getMarket());
  557. String marketName = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  558. message.setMarketName(marketName);
  559. message.setQueryId(cashRecordDTO.getStatus() != 32 ? 115:99);
  560. if (cashRecordDTO.getStatus() != 32) {
  561. log.info("Setting executor to: {}", cashRecordDTO.getExecutor());
  562. message.setExecutor(cashRecordDTO.getExecutor());
  563. log.info("Executor after setting: {}", message.getExecutor());
  564. }
  565. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
  566. }
  567. return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
  568. }
  569. @Override
  570. public PageInfo<CashRecordDTO> financeSelect(Integer pageNum, Integer pageSize, CashRecordDTO cashRecordDTO) {
  571. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  572. // System.out.println(goldDetail.getMarkets());
  573. List<CashRecordDTO> list = cashRefundMapper.financeSelect(cashRecordDTO);
  574. if (list.isEmpty()) {
  575. return new PageInfo<>(list);
  576. }
  577. // 批量收集ID
  578. Set<Integer> relatedIds = new HashSet<>();
  579. Set<Integer> marketIds = new HashSet<>();
  580. Set<Integer> submitterIds = new HashSet<>();
  581. Set<Integer> auditIds = new HashSet<>();
  582. Set<Integer> executorIds = new HashSet<>();
  583. list.forEach(item -> {
  584. if (item.getRelatedId() != null) relatedIds.add(item.getRelatedId());
  585. if (item.getMarket() != null) marketIds.add(item.getMarket());
  586. if (item.getSubmitterId() != null) submitterIds.add(item.getSubmitterId());
  587. if (item.getAuditId() != null) auditIds.add(item.getAuditId());
  588. if (item.getExecutor() != null) executorIds.add(item.getExecutor());
  589. });
  590. // 批量查询
  591. Map<Integer, CashCollection> cashCollectionMap = cashCollectionMapper.selectBatchIds(relatedIds)
  592. .stream().collect(Collectors.toMap(CashCollection::getId, Function.identity()));
  593. Map<Integer, String> marketNameMap = marketMapper.getMarketByIds(marketIds)
  594. .stream().collect(Collectors.toMap(Market::getId, Market::getName));
  595. Map<Integer, String> submitterNameMap = auditMapper.getNamesByIds(submitterIds)
  596. .stream().collect(Collectors.toMap(Admin::getId, Admin::getAdminName));
  597. Map<Integer, LhlAudit> auditMap = cashRefundMapper.getAuditBatch(auditIds)
  598. .stream().collect(Collectors.toMap(LhlAudit::getId, Function.identity()));
  599. Map<String, String> executorNameMap = auditMapper.getNamesByJwcodes(executorIds)
  600. .stream().collect(Collectors.toMap(Admin::getAccount, Admin::getAdminName));
  601. // 处理数据
  602. list.forEach(item -> {
  603. CashCollection cashCollection = cashCollectionMap.get(item.getRelatedId());
  604. if (cashCollection != null) {
  605. processCashCollection(item, cashCollection);
  606. }
  607. String marketName = marketNameMap.get(item.getMarket());
  608. String submitter = submitterNameMap.get(item.getSubmitterId());
  609. LhlAudit lhlAudit = auditMap.get(item.getAuditId());
  610. String executorName = executorNameMap.get(String.valueOf(item.getExecutor()));
  611. item.setMarketName(marketName != null ? marketName : "");
  612. item.setSubmitter(submitter != null ? submitter : "");
  613. item.setExecutorName(executorName != null ? executorName : "");
  614. if (lhlAudit != null) {
  615. item.setAreaServise(lhlAudit.getAreaServise());
  616. item.setAreaFinance(lhlAudit.getAreaFinance());
  617. item.setAreaCharge(lhlAudit.getAreaCharge());
  618. item.setHeadFinance(lhlAudit.getHeadFinance());
  619. }
  620. });
  621. return new PageInfo<>(list);
  622. }
  623. @Override
  624. public PageInfo<CashRecordDTO> financeSelect2(Integer pageNum, Integer pageSize, CashRecordDTO cashRecordDTO) {
  625. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  626. // System.out.println(goldDetail.getMarkets());
  627. List<CashRecordDTO> list = cashRefundMapper.financeSelect(cashRecordDTO);
  628. if (list.isEmpty()) {
  629. return new PageInfo<>(list);
  630. }
  631. // 批量收集ID
  632. Set<Integer> relatedIds = new HashSet<>();
  633. Set<Integer> marketIds = new HashSet<>();
  634. Set<Integer> submitterIds = new HashSet<>();
  635. Set<Integer> auditIds = new HashSet<>();
  636. Set<Integer> executorIds = new HashSet<>();
  637. list.forEach(item -> {
  638. if (item.getRelatedId() != null) relatedIds.add(item.getRelatedId());
  639. if (item.getMarket() != null) marketIds.add(item.getMarket());
  640. if (item.getSubmitterId() != null) submitterIds.add(item.getSubmitterId());
  641. if (item.getAuditId() != null) auditIds.add(item.getAuditId());
  642. if (item.getExecutor() != null) executorIds.add(item.getExecutor());
  643. });
  644. // 批量查询
  645. Map<Integer, CashCollection> cashCollectionMap = cashCollectionMapper.selectBatchIds(relatedIds)
  646. .stream().collect(Collectors.toMap(CashCollection::getId, Function.identity()));
  647. Map<Integer, String> marketNameMap = marketMapper.getMarketByIds(marketIds)
  648. .stream().collect(Collectors.toMap(Market::getId, Market::getName));
  649. Map<Integer, String> submitterNameMap = auditMapper.getNamesByIds(submitterIds)
  650. .stream().collect(Collectors.toMap(Admin::getId, Admin::getAdminName));
  651. Map<Integer, LhlAudit> auditMap = cashRefundMapper.getAuditBatch(auditIds)
  652. .stream().collect(Collectors.toMap(LhlAudit::getId, Function.identity()));
  653. Map<String, String> executorNameMap = auditMapper.getNamesByJwcodes(executorIds)
  654. .stream().collect(Collectors.toMap(Admin::getAccount, Admin::getAdminName));
  655. // 处理数据
  656. list.forEach(item -> {
  657. CashCollection cashCollection = cashCollectionMap.get(item.getRelatedId());
  658. if (cashCollection != null) {
  659. processCashCollection(item, cashCollection);
  660. }
  661. String marketName = marketNameMap.get(item.getMarket());
  662. String submitter = submitterNameMap.get(item.getSubmitterId());
  663. LhlAudit lhlAudit = auditMap.get(item.getAuditId());
  664. String executorName = executorNameMap.get(String.valueOf(item.getExecutor()));
  665. item.setMarketName(marketName != null ? marketName : "");
  666. item.setSubmitter(submitter != null ? submitter : "");
  667. item.setExecutorName(executorName != null ? executorName : "");
  668. if (lhlAudit != null) {
  669. item.setAreaServise(lhlAudit.getAreaServise());
  670. item.setAreaFinance(lhlAudit.getAreaFinance());
  671. item.setAreaCharge(lhlAudit.getAreaCharge());
  672. item.setHeadFinance(lhlAudit.getHeadFinance());
  673. }
  674. });
  675. return new PageInfo<>(list);
  676. }
  677. @Override
  678. public PageInfo<CashRecordDTO> exSelect(Integer pageNum, Integer pageSize, CashRecordDTO cashRecordDTO) {
  679. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  680. // System.out.println(goldDetail.getMarkets());
  681. List<CashRecordDTO> list = cashRefundMapper.exSelect(cashRecordDTO);
  682. System.out.println(list);
  683. if (list.isEmpty()) {
  684. return new PageInfo<>(list);
  685. }
  686. // 批量收集ID
  687. Set<Integer> relatedIds = new HashSet<>();
  688. Set<Integer> marketIds = new HashSet<>();
  689. Set<Integer> submitterIds = new HashSet<>();
  690. Set<Integer> auditIds = new HashSet<>();
  691. Set<Integer> executorIds = new HashSet<>();
  692. list.forEach(item -> {
  693. if (item.getRelatedId() != null) relatedIds.add(item.getRelatedId());
  694. if (item.getMarket() != null) marketIds.add(item.getMarket());
  695. if (item.getSubmitterId() != null) submitterIds.add(item.getSubmitterId());
  696. if (item.getAuditId() != null) auditIds.add(item.getAuditId());
  697. if (item.getExecutor() != null) executorIds.add(item.getExecutor());
  698. });
  699. // 批量查询
  700. Map<Integer, CashCollection> cashCollectionMap = cashCollectionMapper.selectBatchIds(relatedIds)
  701. .stream().collect(Collectors.toMap(CashCollection::getId, Function.identity()));
  702. Map<Integer, String> marketNameMap = marketMapper.getMarketByIds(marketIds)
  703. .stream().collect(Collectors.toMap(Market::getId, Market::getName));
  704. Map<Integer, String> submitterNameMap = auditMapper.getNamesByIds(submitterIds)
  705. .stream().collect(Collectors.toMap(Admin::getId, Admin::getAdminName));
  706. Map<Integer, LhlAudit> auditMap = cashRefundMapper.getAuditBatch(auditIds)
  707. .stream().collect(Collectors.toMap(LhlAudit::getId, Function.identity()));
  708. Map<String, String> executorNameMap = auditMapper.getNamesByJwcodes(executorIds)
  709. .stream().collect(Collectors.toMap(Admin::getAccount, Admin::getAdminName));
  710. // 处理数据
  711. list.forEach(item -> {
  712. CashCollection cashCollection = cashCollectionMap.get(item.getRelatedId());
  713. if (cashCollection != null) {
  714. processCashCollection(item, cashCollection);
  715. }
  716. String marketName = marketNameMap.get(item.getMarket());
  717. String submitter = submitterNameMap.get(item.getSubmitterId());
  718. LhlAudit lhlAudit = auditMap.get(item.getAuditId());
  719. String executorName = executorNameMap.get(String.valueOf(item.getExecutor()));
  720. item.setMarketName(marketName != null ? marketName : "");
  721. item.setSubmitter(submitter != null ? submitter : "");
  722. item.setExecutorName(executorName != null ? executorName : "");
  723. if (lhlAudit != null) {
  724. item.setAreaServise(lhlAudit.getAreaServise());
  725. item.setAreaFinance(lhlAudit.getAreaFinance());
  726. item.setAreaCharge(lhlAudit.getAreaCharge());
  727. item.setHeadFinance(lhlAudit.getHeadFinance());
  728. }
  729. });
  730. return new PageInfo<>(list);
  731. }
  732. @Override
  733. @Transactional(rollbackFor = Exception.class)
  734. public void addOnline(CashRecordRefund cashRecordRefund,String lang) {
  735. try {
  736. if (cashRecordRefund.getJwcode() == null) {
  737. throw new BusinessException("未输入精网号");
  738. }
  739. if (cashRecordRefund.getRefundModel() == null) {
  740. throw new BusinessException("请填充退款类型");
  741. }
  742. if (cashRecordRefund.getRefundReason() == null) {
  743. throw new BusinessException("请填写退款理由");
  744. }
  745. if (cashRecordRefund.getMarket() == null || cashRecordRefund.getMarket().trim().isEmpty()) {
  746. throw new BusinessException("请选择所属地区");
  747. }
  748. String payType = cashRecordRefund.getPayType();
  749. Integer wallet = null;
  750. if (payType == null || payType.trim().isEmpty()) {
  751. throw new SystemException("未传输支付方式");
  752. }
  753. if (payType.equals("Stripe")||payType.equals("PaymentAsia"))
  754. {
  755. wallet = 2;
  756. }
  757. if (payType.equals("FirstData")||payType.equals("Grabpay")||payType.equals("Nets")||payType.equals("PayPal")||payType.equals("IOS"))
  758. {
  759. wallet = 5;
  760. }
  761. if (payType.equals("Stripe2"))
  762. {
  763. wallet = 3;
  764. }
  765. if (payType.equals("iPay88"))
  766. {
  767. wallet = 4;
  768. }
  769. if (payType.equals("E-Transfer"))
  770. {
  771. wallet = 6;
  772. }
  773. if (payType.equals("paysolution"))
  774. {
  775. wallet = 8;
  776. }
  777. UserRegionWallet userRegionWallet = walletMapper.selectWallet(cashRecordRefund.getJwcode(), wallet);
  778. User user = userMapper.selectUserByJwcode(cashRecordRefund.getJwcode());
  779. if (user.getCurrentFreeJune().add(user.getCurrentFreeDecember()).compareTo(BigDecimal.valueOf(cashRecordRefund.getPartRefundFree()))<0){
  780. String errorMsg = languageTranslationUtil.translate("用户钱包余额不足", lang);
  781. throw new BusinessException(errorMsg);
  782. }
  783. if (userRegionWallet == null) {
  784. //初始化钱包
  785. walletMapper.insert(new UserRegionWallet(null, cashRecordRefund.getJwcode(), wallet, BigDecimal.ZERO, new Date(), new Date()));
  786. log.warn("用户钱包不存在,已初始化钱包");
  787. }
  788. if (userRegionWallet.getCurrentPermanentGold().compareTo(BigDecimal.valueOf(cashRecordRefund.getPartRefundGold())) < 0) {
  789. throw new BusinessException("用户钱包金币不足");
  790. }
  791. CashRecordDone cashRecordDonetwo = new CashRecordDone();
  792. cashRecordDonetwo.setAreaServise(cashRecordRefund.getAreaServise());
  793. cashRefundMapper.addAudit(cashRecordDonetwo);
  794. cashRecordRefund.setAuditId(cashRecordDonetwo.getId());
  795. cashRecordRefund.setStatus(20);
  796. //生成订单号后半部分
  797. String orderNumber = cashRecordRefund.getOrderCode();
  798. //构建订单信息
  799. cashRecordRefund.setOrderCode("TK" + orderNumber); //订单号
  800. // 查询市场 ID,增加空值检查
  801. String marketName = cashRecordRefund.getMarket();
  802. // 如果传入的是英文名称,需要转换为中文名称再查询
  803. String marketId = marketMapper.getMarketId(marketName);
  804. if (marketId == null || marketId.trim().isEmpty()) {
  805. // 尝试将英文名称转换为中文后再次查询
  806. String chineseMarketName = translationService.findChineseSimplifiedByTranslation(marketName, "en");
  807. if (chineseMarketName != null && !chineseMarketName.equals(marketName)) {
  808. marketId = marketMapper.getMarketId(chineseMarketName);
  809. }
  810. }
  811. if (marketId == null || marketId.trim().isEmpty()) {
  812. throw new BusinessException("无效的所属地区:" + cashRecordRefund.getMarket());
  813. }
  814. cashRecordRefund.setMarket(String.valueOf(Integer.valueOf(marketId)));
  815. cashRefundMapper.insert(cashRecordRefund);
  816. CashRecordDone cashRecordDone1 = new CashRecordDone();
  817. cashRecordDone1.setId(cashRecordRefund.getOriginalOrderId());
  818. cashRecordDone1.setStatus(6);
  819. if (cashRecordDone1.getId() != null || cashRecordDone1.getOrderCode() != null) {
  820. cashRefundMapper.updateStatus(cashRecordDone1);
  821. } else {
  822. throw new SystemException("提交失败");
  823. }
  824. } catch (BusinessException | SystemException e) {
  825. throw e;
  826. } catch (Exception e) {
  827. log.error("addOnline error", e);
  828. throw new SystemException("提交失败:" + e.getMessage());
  829. }
  830. }
  831. @Override
  832. public PageInfo<FundsDTO> funds(Integer pageNum, Integer pageSize, FundsDTO fundsDTO) {
  833. // 1. 分页查询主数据
  834. PageHelper.startPage(pageNum, pageSize);
  835. if (fundsDTO.getStatuses() == null || fundsDTO.getStatuses().isEmpty()) {
  836. fundsDTO.setStatuses(Arrays.asList(4, 6));
  837. }
  838. List<FundsDTO> list = cashRefundMapper.selectfunds(fundsDTO);
  839. // 2. 收集 status == 6 的记录 ID
  840. List<Integer> needQueryIds = new ArrayList<>();
  841. for (FundsDTO dto : list) {
  842. if (dto.getStatus() != null && dto.getStatus() == 6) {
  843. needQueryIds.add(dto.getId());
  844. }
  845. }
  846. // 3. 批量查询 refundDetail 信息(用于负数处理)
  847. if (!needQueryIds.isEmpty()) {
  848. List<FundsDTO> detailList = cashRefundMapper.selectRefundCount(needQueryIds);
  849. Map<Integer, FundsDTO> detailMap = new HashMap<>();
  850. for (FundsDTO detail : detailList) {
  851. // 假设 detail.getRelatedId() 对应主表的 id
  852. detailMap.put(detail.getRelatedId(), detail);
  853. }
  854. // 回填 refundAmount(取负)和 refundCurrency
  855. for (FundsDTO dto : list) {
  856. if (dto.getStatus() != null && dto.getStatus() == 6) {
  857. FundsDTO detail = detailMap.get(dto.getId());
  858. if (detail != null) {
  859. BigDecimal amount = detail.getRefundAmount();
  860. if (amount != null) {
  861. dto.setRefundAmount(amount.negate()); // 转为负数
  862. } else {
  863. dto.setRefundAmount(null); // 或设为 BigDecimal.ZERO
  864. }
  865. dto.setRefundCurrency(detail.getRefundCurrency());
  866. }
  867. }
  868. }
  869. }
  870. // 4. 收集所有需要转换的 regionId 和 currencyId
  871. Set<Integer> regionIds = new HashSet<>();
  872. Set<Integer> currencyIds = new HashSet<>();
  873. Set<Integer> reCurrencyIds = new HashSet<>();
  874. for (FundsDTO dto : list) {
  875. if (dto.getMarket() != null) {
  876. regionIds.add(dto.getMarket());
  877. }
  878. if (dto.getPaymentCurrency() != null) {
  879. currencyIds.add(dto.getPaymentCurrency());
  880. }
  881. if (dto.getReceivedCurrency() != null) {
  882. reCurrencyIds.add(dto.getReceivedCurrency());
  883. }
  884. }
  885. // 5. 批量查询地区字典
  886. Map<Integer, String> regionMap = new HashMap<>();
  887. if (!regionIds.isEmpty()) {
  888. List<Region> regions = refundMapper.selectByIds(new ArrayList<>(regionIds));
  889. for (Region region : regions) {
  890. regionMap.put(region.getId(), region.getName());
  891. }
  892. }
  893. // 6. 批量查询币种字典
  894. Map<Integer, String> currencyMap = new HashMap<>();
  895. if (!currencyIds.isEmpty()) {
  896. List<Currency> currencies = refundMapper.selectByCIds(new ArrayList<>(currencyIds));
  897. for (Currency currency : currencies) {
  898. currencyMap.put(currency.getId(), currency.getName()); // 或 getCode(),按需调整
  899. }
  900. }
  901. Map<Integer, String> reCurrencyMap = new HashMap<>();
  902. if (!reCurrencyIds.isEmpty()) {
  903. List<Currency> reCurrencies = refundMapper.selectByCIds(new ArrayList<>(reCurrencyIds));
  904. for (Currency reCurrency : reCurrencies) {
  905. reCurrencyMap.put(reCurrency.getId(), reCurrency.getName()); // 或 getCode(),按需调整
  906. }
  907. }
  908. // 7. 回填地区名称和币种名称到 DTO
  909. for (FundsDTO dto : list) {
  910. dto.setMarketName(regionMap.get(dto.getMarket()));
  911. dto.setPaymentCurrencyName(currencyMap.get(dto.getPaymentCurrency()));
  912. dto.setReceivedCurrencyName(reCurrencyMap.get(dto.getReceivedCurrency()));
  913. }
  914. // 8. 返回分页结果
  915. return new PageInfo<>(list);
  916. }
  917. /**
  918. * 计算用户指定钱包列表的总可用余额
  919. * @param jwcode 用户标识
  920. * @param records 原始充值流水列表用于提取 wallet_id 列表
  921. * @return 总余额BigDecimal
  922. */
  923. private BigDecimal getUserTotalBalance(Integer jwcode, List<UserWalletRecord> records) {
  924. // 提取涉及到的 wallet_id 列表(去重)
  925. List<Integer> walletIds = records.stream()
  926. .map(UserWalletRecord::getWalletId)
  927. .distinct()
  928. .collect(Collectors.toList());
  929. if (CollectionUtils.isEmpty(walletIds)) {
  930. return BigDecimal.ZERO;
  931. }
  932. // 批量查询钱包当前余额(避免 N+1 查询)
  933. List<UserRegionWallet> wallets = walletMapper.selectWalletsByJwcodeAndIds(jwcode, walletIds);
  934. // 汇总余额
  935. return wallets.stream()
  936. .map(UserRegionWallet::getCurrentPermanentGold)
  937. .filter(Objects::nonNull)
  938. .reduce(BigDecimal.ZERO, BigDecimal::add);
  939. }
  940. }