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.

1010 lines
49 KiB

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