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.

862 lines
41 KiB

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
3 months ago
  1. package com.example.demo.serviceImpl.cash;
  2. import com.example.demo.Util.JWTUtil;
  3. import com.example.demo.Util.LanguageTranslationUtil;
  4. import com.example.demo.config.RabbitMQConfig;
  5. import com.example.demo.domain.DTO.AddFundsDTO;
  6. import com.example.demo.domain.DTO.PerformanceAdjustmentDTO;
  7. import com.example.demo.domain.DTO.PerformanceDTO;
  8. import com.example.demo.domain.entity.*;
  9. import com.example.demo.domain.vo.cash.*;
  10. import com.example.demo.domain.vo.coin.AreaInfo;
  11. import com.example.demo.domain.vo.coin.GoldUser;
  12. import com.example.demo.domain.vo.coin.Messages;
  13. import com.example.demo.domain.vo.coin.Result;
  14. import com.example.demo.mapper.cash.CashCollectionMapper;
  15. import com.example.demo.mapper.coin.MarketMapper;
  16. import com.example.demo.mapper.coin.UserMapper;
  17. import com.example.demo.service.cash.CashCollectionService;
  18. import com.example.demo.service.coin.RechargeActivityCenterService;
  19. import com.github.pagehelper.PageHelper;
  20. import com.github.pagehelper.PageInfo;
  21. import jakarta.servlet.http.HttpServletRequest;
  22. import lombok.extern.slf4j.Slf4j;
  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.util.CollectionUtils;
  28. import org.springframework.web.bind.annotation.RequestHeader;
  29. import org.springframework.web.context.request.RequestContextHolder;
  30. import org.springframework.web.context.request.ServletRequestAttributes;
  31. import java.math.BigDecimal;
  32. import java.time.LocalDateTime;
  33. import java.time.ZoneOffset;
  34. import java.util.*;
  35. import java.util.stream.Collectors;
  36. /**
  37. * @program: gold-java
  38. * @ClassName cashCollectionServiceImpl
  39. * @description: 处理收款相关业务逻辑
  40. * @author: Ethan
  41. * @create: 202509-26 11:23
  42. * @Version 1.0
  43. **/
  44. @Service
  45. @Slf4j
  46. public class CashCollectionServiceImpl implements CashCollectionService {
  47. @Autowired
  48. private CashCollectionMapper cashCollectionMapper;
  49. @Autowired
  50. private UserMapper userMapper;
  51. @Autowired
  52. private MarketMapper marketMapper;
  53. @Autowired
  54. private RabbitTemplate rabbitTemplate;
  55. @Autowired
  56. private LanguageTranslationUtil languageTranslationUtil;
  57. @Autowired
  58. private RechargeActivityCenterService rechargeActivityCenterService;
  59. //新增收款订单
  60. @Override
  61. public String add(CashCollection cashCollection,@RequestHeader(defaultValue = "zh_CN") String lang) {
  62. if (cashCollection.getJwcode() == null) {
  63. throw new IllegalArgumentException("精网号不能为空");
  64. }
  65. if (cashCollection.getJwcode() < 10000000 || cashCollection.getJwcode() > 99999999) {
  66. throw new IllegalArgumentException("精网号必须为 8 位");
  67. }
  68. if (cashCollection.getName() == null || cashCollection.getName().isEmpty()){
  69. throw new IllegalArgumentException("客户姓名不能为空");
  70. }
  71. if (cashCollection.getActivity() == null || cashCollection.getActivity().isEmpty()) {
  72. throw new IllegalArgumentException("活动不能为空");
  73. }
  74. if (cashCollection.getWalletId() == null || cashCollection.getWalletId() < 1 || cashCollection.getWalletId() > 10) {
  75. throw new IllegalArgumentException("钱包 ID 为 1~10");
  76. }
  77. if (cashCollection.getGoodsName() == null|| cashCollection.getGoodsName().isEmpty()) {
  78. throw new IllegalArgumentException("产品名称不能为空");
  79. }
  80. if (cashCollection.getGoodsName().equals("金币充值")) {
  81. if (cashCollection.getPermanentGold() == 0 && cashCollection.getFreeGold() == 0) {
  82. throw new IllegalArgumentException("金币数量不能为空");
  83. }
  84. }
  85. if (!cashCollection.getGoodsName().equals("金币充值")) {
  86. if (cashCollection.getGoodNum() == 0) {
  87. throw new IllegalArgumentException("产品数量不能为空");
  88. }
  89. if (cashCollection.getNumUnit() == null|| cashCollection.getNumUnit().isEmpty()) {
  90. throw new IllegalArgumentException("数量单位不能为空");
  91. }
  92. }
  93. if (cashCollection.getPaymentCurrency() == null || cashCollection.getPaymentCurrency().isEmpty()) {
  94. throw new IllegalArgumentException("支付币种不能为空");
  95. }
  96. if (cashCollection.getPaymentAmount() == null || cashCollection.getPaymentAmount().compareTo(BigDecimal.ZERO) == 0) {
  97. throw new IllegalArgumentException("支付金额不能为空");
  98. }
  99. if (cashCollection.getPayType() == null|| cashCollection.getPayType().isEmpty()) {
  100. throw new IllegalArgumentException("支付方式不能为空");
  101. }
  102. if (cashCollection.getReceivedMarket() == null||cashCollection.getReceivedMarket().isEmpty()) {
  103. throw new IllegalArgumentException("到账地区不能为空");
  104. }
  105. if (cashCollection.getPayTime() == null) {
  106. throw new IllegalArgumentException("付款时间不能为空");
  107. }
  108. AreaInfo areaInfo = rechargeActivityCenterService.queryActivityAreaById(Integer.parseInt(cashCollection.getActivity()));
  109. // 校验钱包 ID 和到账地区的对应关系
  110. validateWalletAndMarket(cashCollection.getWalletId(), cashCollection.getReceivedMarket());
  111. //生成订单号后半部分
  112. String orderNumber = UUID.randomUUID().toString().replaceAll("-", "");
  113. CashRecord cashRecord = new CashRecord();
  114. //构建订单信息
  115. cashRecord.setOrderCode("XJ_" + orderNumber); //订单号
  116. cashRecord.setJwcode(cashCollection.getJwcode()); //精网号
  117. cashRecord.setName(cashCollection.getName()); //客户姓名
  118. cashRecord.setActivity(cashCollection.getActivity()); // 活动
  119. cashRecord.setGoodsName(cashCollection.getGoodsName()); //商品名称
  120. cashRecord.setGoodNum(cashCollection.getGoodNum()); //商品数量
  121. cashRecord.setNumUnit(cashCollection.getNumUnit()); //数量单位
  122. cashRecord.setPermanentGold(cashCollection.getPermanentGold()); //永久金币
  123. cashRecord.setFreeGold(cashCollection.getFreeGold()); //免费金币
  124. cashRecord.setWalletId(cashCollection.getWalletId()); // 钱包 ID
  125. cashRecord.setPaymentCurrency(cashCollection.getPaymentCurrency()); //付款币种
  126. cashRecord.setPaymentAmount(cashCollection.getPaymentAmount()); //付款金额
  127. cashRecord.setReceivedMarket(cashCollection.getReceivedMarket()); //到账地区
  128. cashRecord.setPayType(cashCollection.getPayType()); //支付方式
  129. cashRecord.setPayTime(cashCollection.getPayTime()); //付款时间
  130. cashRecord.setVoucher(cashCollection.getVoucher()); //转账凭证
  131. cashRecord.setRemark(cashCollection.getRemark()); //备注
  132. cashRecord.setStatus(0); //订单状态:付款线下财务待审核
  133. cashRecord.setSubmitterId(cashCollection.getSubmitterId()); //提交人 ID
  134. cashRecord.setSubmitterMarket(cashCollection.getSubmitterMarket());
  135. cashRecord.setOrderType(1); //订单类型:1-收款
  136. cashRecord.setMarket(cashCollection.getMarket());
  137. if(areaInfo.getArea().equals("0")){
  138. cashRecord.setPerformanceMarket(cashCollection.getMarket());
  139. }else {
  140. cashRecord.setPerformanceMarket(areaInfo.getArea());
  141. }
  142. //地区,根据 jwcode 插入
  143. //cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(cashRecord.getJwcode()));
  144. //插入新收款订单
  145. cashCollectionMapper.add(cashRecord);
  146. // 发送收款创建消息
  147. Messages message = new Messages();
  148. message.setJwcode(cashRecord.getJwcode());
  149. message.setName(cashRecord.getName());
  150. message.setStatus(cashRecord.getStatus());
  151. message.setDesc("的现金收款申请待审核,前往审核");
  152. message.setTitle("现金管理--收款处理");
  153. message.setType(0);
  154. message.setTypeId(cashRecord.getId());
  155. message.setMarket(Integer.valueOf(cashRecord.getMarket()));
  156. String marketName = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  157. message.setMarketName(marketName);
  158. message.setQueryId(67);
  159. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
  160. return "添加成功";
  161. }
  162. @Override
  163. public String addFreeCoin(CashCollection cashCollection,@RequestHeader(defaultValue = "zh_CN") String lang) {
  164. if (cashCollection.getJwcode() == null) {
  165. throw new IllegalArgumentException("精网号不能为空");
  166. }
  167. if (cashCollection.getJwcode() < 10000000 || cashCollection.getJwcode() > 99999999) {
  168. throw new IllegalArgumentException("精网号必须为8位");
  169. }
  170. if (cashCollection.getName() == null || cashCollection.getName().isEmpty()){
  171. throw new IllegalArgumentException("客户姓名不能为空");
  172. }
  173. if (cashCollection.getActivity() == null || cashCollection.getActivity().isEmpty()) {
  174. throw new IllegalArgumentException("活动不能为空");
  175. }
  176. if (cashCollection.getFreeGold() == 0) {
  177. throw new IllegalArgumentException("免费金币数量不能为空");
  178. }
  179. //生成订单号后半部分
  180. String orderNumber = UUID.randomUUID().toString().replaceAll("-", "");
  181. CashRecord cashRecord = new CashRecord();
  182. //构建订单信息
  183. cashRecord.setOrderCode("XJ_" + orderNumber); //订单号
  184. cashRecord.setJwcode(cashCollection.getJwcode()); //精网号
  185. cashRecord.setName(cashCollection.getName()); //客户姓名
  186. cashRecord.setActivity(cashCollection.getActivity()); // 活动
  187. cashRecord.setGoodsName("免费金币赠送"); //商品名称
  188. cashRecord.setFreeGold(cashCollection.getFreeGold()); //免费金币
  189. cashRecord.setRemark(cashCollection.getRemark()); //备注
  190. cashRecord.setStatus(0); //订单状态:付款线下财务待审核
  191. cashRecord.setSubmitterId(cashCollection.getSubmitterId()); //提交人ID
  192. cashRecord.setSubmitterMarket(cashCollection.getSubmitterMarket());
  193. cashRecord.setOrderType(1); //订单类型:1-收款
  194. cashRecord.setMarket(cashCollection.getMarket());
  195. //地区,根据jwcode插入
  196. //cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(cashRecord.getJwcode()));
  197. //插入新收款订单
  198. cashCollectionMapper.add(cashRecord);
  199. // 发送收款创建消息
  200. Messages message = new Messages();
  201. message.setJwcode(cashRecord.getJwcode());
  202. message.setName(cashRecord.getName());
  203. message.setStatus(cashRecord.getStatus());
  204. message.setDesc("的现金收款申请待审核,请前往审核");
  205. message.setTitle("现金收款--现金收款");
  206. message.setType(1);
  207. message.setTypeId(cashRecord.getId());
  208. message.setMarket(Integer.valueOf(cashRecord.getMarket()));
  209. String marketName = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  210. message.setMarketName(marketName);
  211. message.setQueryId(67);
  212. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
  213. return "添加成功";
  214. }
  215. //撤回未审核的订单
  216. @Override
  217. public String cancel(String orderCode) {
  218. // 查询订单是否存在
  219. CashRecord cashRecord = cashCollectionMapper.selectByOrderCode(orderCode);
  220. if (cashRecord == null) {
  221. throw new IllegalArgumentException("订单不存在");
  222. }
  223. if (cashRecord.getStatus() != 0) {
  224. throw new IllegalArgumentException("订单状态不符合条件");
  225. }
  226. // 更新订单状态为撤回状态(5)
  227. int rows = cashCollectionMapper.updateStatus(orderCode, 5);
  228. // 更新与该订单关联的消息记录的 flag 字段为 1
  229. try {
  230. // 根据订单ID查找关联的消息记录
  231. Messages message = new Messages();
  232. message.setTypeId(cashRecord.getId()); // 订单ID作为消息的 typeId
  233. message.setType(0); // 消息类型为收款
  234. // 更新消息的 flag 字段为 1
  235. int messageRows = cashCollectionMapper.updateMessageFlagByTypeIdAndType(
  236. message.getTypeId(), message.getType(), 1);
  237. if (messageRows <= 0) {
  238. log.warn("未找到与订单 {} 关联的消息记录", orderCode);
  239. }
  240. } catch (Exception e) {
  241. log.error("更新消息状态失败,订单号:{}", orderCode, e);
  242. // 可选择抛出异常或记录日志后继续执行
  243. }
  244. return rows > 0 ? "撤回成功" : "撤回失败";
  245. }
  246. //编辑并重新提交收款订单
  247. @Override
  248. public String reSubmit(CashRecord cashRecord,@RequestHeader(defaultValue = "zh_CN") String lang) {
  249. if (cashRecord.getJwcode() == null) {
  250. throw new IllegalArgumentException("精网号不能为空");
  251. }
  252. if (cashRecord.getJwcode() < 10000000 || cashRecord.getJwcode() > 99999999) {
  253. throw new IllegalArgumentException("精网号必须为 8 位");
  254. }
  255. if (cashRecord.getName() == null) {
  256. throw new IllegalArgumentException("客户姓名不能为空");
  257. }
  258. if (cashRecord.getActivity() == null) {
  259. throw new IllegalArgumentException("活动不能为空");
  260. }
  261. if (cashRecord.getGoodsName() == null) {
  262. throw new IllegalArgumentException("商品名不能为空");
  263. }
  264. if (cashRecord.getGoodsName().equals("金币充值")) {
  265. if (cashRecord.getPermanentGold() == 0 && cashRecord.getFreeGold() == 0) {
  266. throw new IllegalArgumentException("金币数量不能为空");
  267. }if (cashRecord.getPermanentGold() == 0){
  268. throw new IllegalArgumentException("永久金币数量不能为空");
  269. }
  270. if (cashRecord.getWalletId() == null) {
  271. throw new IllegalArgumentException("钱包 ID 不能为空");
  272. }
  273. }
  274. if (!cashRecord.getGoodsName().equals("金币充值")) {
  275. if (cashRecord.getGoodNum() == 0) {
  276. throw new IllegalArgumentException("产品数量不能为空");
  277. }
  278. if (cashRecord.getNumUnit() == null) {
  279. throw new IllegalArgumentException("数量单位不能为空");
  280. }
  281. }
  282. if (cashRecord.getPaymentCurrency() == null) {
  283. throw new IllegalArgumentException("支付币种不能为空");
  284. }
  285. if (cashRecord.getPaymentAmount() == null || cashRecord.getPaymentAmount().compareTo(BigDecimal.ZERO) == 0) {
  286. throw new IllegalArgumentException("支付金额不能为空");
  287. }
  288. if (cashRecord.getPayType() == null) {
  289. throw new IllegalArgumentException("支付方式不能为空");
  290. }
  291. if (cashRecord.getReceivedMarket() == null) {
  292. throw new IllegalArgumentException("到账地区不能为空");
  293. }
  294. if (cashRecord.getPayTime() == null) {
  295. throw new IllegalArgumentException("付款时间不能为空");
  296. }
  297. // 校验钱包 ID 和到账地区的对应关系
  298. validateWalletAndMarket(cashRecord.getWalletId(), cashRecord.getReceivedMarket());
  299. CashRecord status = cashCollectionMapper.selectByOrderCode(cashRecord.getOrderCode());
  300. if (!status.getStatus().equals(5)) {
  301. throw new IllegalArgumentException("只允许编辑已撤回订单");
  302. }
  303. //地区,根据 jwcode 插入(弃用,插入前调用接口获取地区和姓名,之后前端传入)
  304. //cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(cashRecord.getJwcode()));
  305. int rows = cashCollectionMapper.updateByOrderCode(cashRecord);
  306. if (rows > 0) {
  307. // 发送收款创建消息
  308. Messages message = new Messages();
  309. message.setJwcode(cashRecord.getJwcode());
  310. message.setName(cashRecord.getName());
  311. message.setStatus(cashRecord.getStatus());
  312. message.setDesc("的现金收款申请待审核,前往审核");
  313. message.setTitle("现金管理--收款处理");
  314. message.setType(0);
  315. message.setTypeId(cashRecord.getId());
  316. message.setMarket(Integer.valueOf(cashRecord.getMarket()));
  317. String marketName = marketMapper.getMarketNameById(String.valueOf(message.getMarket()));
  318. message.setMarketName(marketName);
  319. message.setQueryId(67);
  320. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
  321. }
  322. return rows > 0 ? "重新提交成功" : "重新提交失败";
  323. }
  324. //多条件查询收款订单列表
  325. @Override
  326. public PageInfo<CashCollection> selectCollection(Integer pageNum, Integer pageSize, CashCollection cashCollection) {
  327. /* //将操作人的地区列表改为id
  328. List<String> markets = marketMapper.getMarketIds(cashCollection.getMarkets());
  329. if (markets.contains("9") || markets.contains("9999")) {
  330. markets = null;
  331. }*/
  332. // cashCollection.setReceivedMarket(marketMapper.getMarketId(cashCollection.getReceivedMarket()));
  333. if (cashCollection.getCashRoleId() == 2) {
  334. //角色是总部时,若不特地传状态,传1346,sql处理为(1,3,4,6)筛选,
  335. if (cashCollection.getStatus() == null) {
  336. cashCollection.setStatus(1346);
  337. }
  338. cashCollection.setSubmitterId(null);
  339. cashCollection.setReceivedMarket(null);
  340. cashCollection.setSubmitterMarket(null);
  341. }
  342. if (cashCollection.getCashRoleId() == 1) {
  343. //角色是地方财务,提交人置空不设筛选条件,仅按收款地区、提交人地区筛选()
  344. if (cashCollection.getStatus() == null) {
  345. cashCollection.setStatus(123460);
  346. }
  347. //状态为待审核和已驳回时按照提交人地区筛选
  348. if (cashCollection.getStatus() == 0 || cashCollection.getStatus() == 2) {
  349. cashCollection.setReceivedMarket(null);
  350. }
  351. //状态为已通过和Link通过时,满足收款地区或提交人地区即可
  352. /* if (cashCollection.getStatus() == 13) {
  353. cashCollection.setSubmitterId(null);
  354. }*/
  355. //状态为13 或46,已通过或已完成和已退款,满足收款地区或提交人地区即可,
  356. cashCollection.setSubmitterId(null);
  357. }
  358. if (cashCollection.getCashRoleId() == 0) {
  359. //角色是地方财务,提交人置空不设筛选条件---仅当角色是0 地方客服时,按提交人筛选
  360. if (cashCollection.getStatus() == null) {
  361. cashCollection.setStatus(1234560);
  362. }
  363. cashCollection.setSubmitterId(cashCollection.getSubmitterId());
  364. cashCollection.setReceivedMarket(null);
  365. }
  366. // cashCollection.setMarkets(markets);
  367. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  368. List<CashCollection> cashCollections = cashCollectionMapper.selectCollection1(pageNum, pageSize, cashCollection);
  369. return new PageInfo<>(cashCollections);
  370. }
  371. //补全手续费等内容
  372. @Override
  373. @Transactional(rollbackFor = Exception.class)
  374. public String complete(CashRecord cashRecord) {
  375. if (!Objects.equals(cashRecord.getPaymentCurrency(), cashRecord.getReceivedCurrency())
  376. && ("Stripe".equals(cashRecord.getPayType()) || "Paypal".equals(cashRecord.getPayType()))) {
  377. return "支付币种与收款币种不一致";
  378. }
  379. int rows = cashCollectionMapper.complete(cashRecord);
  380. String goodsName = cashCollectionMapper.selectGoodsNameByCode(cashRecord.getOrderCode());
  381. if (goodsName != null && goodsName.equals("金币充值")) {
  382. cashRecord.setOrderCode(cashRecord.getOrderCode().replace("XJ_", "XJCZ_"));
  383. //修改金币订单
  384. cashCollectionMapper.updateGoldOrder(cashRecord);
  385. }
  386. return rows > 0 ? "编辑成功" : "编辑失败";
  387. }
  388. //根据精网号查询姓名和地区
  389. @Override
  390. public Result getNameAndMarket(Integer jwcode,@RequestHeader(defaultValue = "zh_CN") String lang) {
  391. try {
  392. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  393. String token = request.getHeader("token");
  394. Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
  395. if (admin != null) {
  396. List<String> list = Arrays.asList(admin.getMarkets().split(","));
  397. List<String> markets = marketMapper.getMarketIds(list);
  398. // 检查用户是否存在
  399. int userCount = cashCollectionMapper.checkUserExists(jwcode);
  400. if (userCount == 0) {
  401. String message = languageTranslationUtil.translate("精网号有误!请检查", lang);
  402. return Result.error(message);
  403. }
  404. if (markets.contains("9") || markets.contains("9999")) {
  405. // 有特殊权限,可访问所有用户
  406. User user = new User();
  407. user.setMarket(cashCollectionMapper.getMarketByJwcode(jwcode));
  408. user.setName(cashCollectionMapper.getNameByJwcode(jwcode));
  409. user.setMarketName(cashCollectionMapper.getMarketNameByJwcode(jwcode));
  410. return Result.success(user);
  411. } else {
  412. // 检查用户所在市场是否在管理员权限范围内
  413. String userMarket = cashCollectionMapper.getMarketByJwcode(jwcode);
  414. if (userMarket != null && markets.contains(userMarket)) {
  415. // 有权限访问,返回用户信息
  416. User user = new User();
  417. user.setMarket(userMarket);
  418. user.setName(cashCollectionMapper.getNameByJwcode(jwcode));
  419. user.setMarketName(cashCollectionMapper.getMarketNameByJwcode(jwcode));
  420. return Result.success(user);
  421. } else {
  422. // 无权限,返回用户所属地区
  423. String userMarketName = cashCollectionMapper.getMarketNameByJwcode(jwcode);
  424. String translatedMarketName = languageTranslationUtil.translate(userMarketName, lang);
  425. String message = languageTranslationUtil.translate("无权限访问", lang);
  426. return Result.errorWithData(message, java.util.Map.of("market", translatedMarketName));
  427. }
  428. }
  429. } else {
  430. // admin 为 null,即权限验证失败
  431. String userMarketName = cashCollectionMapper.getMarketNameByJwcode(jwcode);
  432. String translatedMarketName = languageTranslationUtil.translate(userMarketName, lang);
  433. String message = languageTranslationUtil.translate("无权限访问", lang);
  434. return Result.errorWithData(message, java.util.Map.of("market", translatedMarketName));
  435. }
  436. } catch (Exception e) {
  437. e.printStackTrace();
  438. String errorMessage = languageTranslationUtil.translate("精网号有误!请检查", lang);
  439. return Result.error(errorMessage);
  440. }
  441. }
  442. //获取收款活动列表
  443. @Override
  444. public List<RechargeActivity> getActivityList() {
  445. LocalDateTime now = LocalDateTime.now();
  446. return cashCollectionMapper.getActivityList(now);
  447. }
  448. //同步g_order订单到cash_record表
  449. @Override
  450. public Object syncToCashRecord() {
  451. int total = 0;
  452. while (true) {
  453. List<GOrder> gOrders = cashCollectionMapper.getUnSync(50);
  454. if (CollectionUtils.isEmpty(gOrders)) {
  455. break;
  456. }
  457. try {
  458. // 每批独立事务
  459. processBatch(gOrders);
  460. total += gOrders.size();
  461. log.info("✅ 同步完成一批,数量: {}, 累计: {}", gOrders.size(), total);
  462. } catch (Exception e) {
  463. List<Integer> failedIds = gOrders.stream().map(GOrder::getId).collect(Collectors.toList());
  464. log.error("失败订单ID: {}", failedIds);
  465. // 可存入 error_log 表,供人工处理
  466. // 这里选择继续下一批(容忍部分失败)
  467. }
  468. if (gOrders.size() < 50) {
  469. break; // 最后一批
  470. }
  471. }
  472. return "同步完毕,成功处理 " + total + " 条";
  473. }
  474. @Override
  475. @Transactional(rollbackFor = Exception.class)
  476. public void processBatch(List<GOrder> gOrders) {
  477. for (GOrder gOrder : gOrders) {
  478. CashRecord cashRecord = new CashRecord();
  479. //构建基础信息
  480. cashRecord.setOrderType(1);
  481. cashRecord.setJwcode(gOrder.getJwcode());
  482. String name=cashCollectionMapper.getNameByJwcode(gOrder.getJwcode());
  483. if (name!=null){
  484. cashRecord.setName(name);
  485. }else cashRecord.setName("未知");
  486. cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(gOrder.getJwcode()));
  487. cashRecord.setPerformanceMarket(cashRecord.getMarket());
  488. if (gOrder.getType().equals("gold")){ //充金豆
  489. cashRecord.setActivity("99");
  490. cashRecord.setGoodsName("Link充值金豆");
  491. cashRecord.setRemark("Link充值金豆");
  492. cashRecord.setNumUnit("个");
  493. cashRecord.setPermanentGold(0);
  494. cashRecord.setGoodNum(gOrder.getCount());
  495. }
  496. if (gOrder.getType().equals("gold_coin")){//充金币
  497. cashRecord.setActivity("98");
  498. cashRecord.setGoodsName("Link充值金币");
  499. cashRecord.setRemark("Link充值金币");
  500. cashRecord.setPermanentGold(gOrder.getCount()*100);
  501. cashRecord.setGoodNum(0);
  502. }
  503. cashRecord.setOrderCode(gOrder.getOrderNo());
  504. if (gOrder != null) {
  505. switch (gOrder.getPayStyle()) {
  506. case 3:
  507. cashRecord.setPayType("IOS内购");
  508. cashRecord.setBankCode(gOrder.getIosTransactionId());
  509. cashRecord.setReceivedMarket("4");
  510. cashRecord.setPerformanceMarket("4");
  511. cashRecord.setPayload("IOS");
  512. break;
  513. case 5:
  514. cashRecord.setPayType("Stripe");
  515. cashRecord.setReceivedMarket("13");
  516. cashRecord.setPayload("Stripe");
  517. break;
  518. case 6:
  519. cashRecord.setPayType("PaymentAsia");
  520. cashRecord.setReceivedMarket("13");
  521. cashRecord.setPayload("PaymentAsia");
  522. break;
  523. case 7:
  524. cashRecord.setPayType("Ipay88");
  525. cashRecord.setReceivedMarket("5");
  526. cashRecord.setPayload("Ipay88");
  527. break;
  528. case 9:
  529. cashRecord.setPayType("FirstData");
  530. cashRecord.setReceivedMarket("4");
  531. cashRecord.setBankCode(gOrder.getFirstdataIpgTransactionId());
  532. cashRecord.setPayload("FirstData");
  533. break;
  534. case 10:
  535. cashRecord.setPayType("PaySolutions");
  536. cashRecord.setReceivedMarket("24018");
  537. cashRecord.setPayload("PaySolutions");
  538. break;
  539. case 15:
  540. cashRecord.setPayType("Stripe2");
  541. cashRecord.setReceivedMarket("4");
  542. cashRecord.setPayload("Stripe2");
  543. default:
  544. break;
  545. }
  546. }
  547. cashRecord.setFreeGold(0);
  548. cashRecord.setPaymentCurrency("");
  549. cashRecord.setPaymentAmount(BigDecimal.valueOf(0));
  550. //转换时间戳,加上时区偏移
  551. cashRecord.setPayTime(LocalDateTime.ofEpochSecond(gOrder.getSuccessTime(), 0, ZoneOffset.of("+08:00")));
  552. cashRecord.setAuditTime(LocalDateTime.ofEpochSecond(gOrder.getSuccessTime(), 0, ZoneOffset.of("+08:00")));
  553. cashRecord.setStatus(3);
  554. cashRecord.setSubmitterId(99999);
  555. //存入现金库
  556. cashCollectionMapper.add(cashRecord);
  557. cashCollectionMapper.markSynced(gOrder.getId());
  558. }
  559. }
  560. @Override
  561. public CashCollection selectById(CashCollection cashCollection) {
  562. return cashCollectionMapper.selectById(cashCollection.getId());
  563. }
  564. //根据goldcoin订单号查询收款订单
  565. @Override
  566. public CashCollection selectByGoldCoinOrderCode(String orderNo) {
  567. return cashCollectionMapper.selectByGoldCoinOrderCode(orderNo);
  568. }
  569. //多条件查询收款订单列表
  570. @Override
  571. public PageInfo<PerformanceVO> performanceSelect(Integer pageNum, Integer pageSize, PerformanceDTO performanceDTO) {
  572. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  573. List<PerformanceVO> performanceVOs = cashCollectionMapper.performanceSelect(performanceDTO);
  574. return new PageInfo<>(performanceVOs);
  575. }
  576. // 根据精网号和钱包 ID 查询用户钱包明细列表(分页)
  577. @Override
  578. public PageInfo<UserWalletRecordVO> selectWalletRecordsByJwcodeAndWalletId(
  579. Integer pageNum, Integer pageSize, Integer jwcode, Integer walletId) {
  580. PageHelper.startPage(pageNum, pageSize);
  581. List<UserWalletRecordVO> records = cashCollectionMapper.selectWalletRecordsByJwcodeAndWalletId(jwcode, walletId);
  582. return new PageInfo<>(records);
  583. }
  584. // 根据精网号和地区查询用户的所有钱包 ID 和金币数量(包含用户名和地区)(分页)
  585. @Override
  586. public PageInfo<UserWalletVO> selectUserWallets(Integer jwcode, String market, Integer pageNum, Integer pageSize, String sortField, String sortOrder, Integer sortWalletId) {
  587. // 第一步:先查询符合条件的精网号列表(分页)
  588. PageHelper.startPage(pageNum, pageSize);
  589. List<Integer> jwcodeList = cashCollectionMapper.selectDistinctJwcodes(jwcode, market, sortField, sortOrder, sortWalletId);
  590. PageInfo<Integer> jwcodePageInfo = new PageInfo<>(jwcodeList);
  591. // 如果没有符合条件的记录,直接返回空结果
  592. if (jwcodeList == null || jwcodeList.isEmpty()) {
  593. PageInfo<UserWalletVO> emptyResult = new PageInfo<>();
  594. emptyResult.setList(new ArrayList<>());
  595. emptyResult.setTotal(0);
  596. emptyResult.setPages(0);
  597. emptyResult.setPageNum(pageNum);
  598. emptyResult.setPageSize(pageSize);
  599. return emptyResult;
  600. }
  601. // 第二步:根据精网号列表查询用户的钱包信息(不分页,返回这些精网号的所有钱包)
  602. List<UserWalletVO> allWallets = cashCollectionMapper.selectUserWalletsByJwcodes(jwcodeList, market, sortField, sortOrder, sortWalletId);
  603. // 第三步:将钱包信息按精网号分组组装
  604. Map<Integer, UserWalletVO> userWalletMap = new LinkedHashMap<>();
  605. for (UserWalletVO wallet : allWallets) {
  606. Integer key = wallet.getJwcode();
  607. if (!userWalletMap.containsKey(key)) {
  608. UserWalletVO userWallet = new UserWalletVO();
  609. userWallet.setJwcode(wallet.getJwcode());
  610. userWallet.setUserName(wallet.getUserName());
  611. userWallet.setMarket(wallet.getMarket());
  612. userWallet.setMarketName(wallet.getMarketName());
  613. userWallet.setWalletList(new ArrayList<>());
  614. userWalletMap.put(key, userWallet);
  615. }
  616. // 添加钱包明细
  617. if (wallet.getWalletList() != null) {
  618. userWalletMap.get(key).getWalletList().addAll(wallet.getWalletList());
  619. }
  620. }
  621. // 第四步:按照精网号列表的顺序构建最终结果
  622. List<UserWalletVO> result = new ArrayList<>();
  623. for (Integer jwc : jwcodeList) {
  624. UserWalletVO userWallet = userWalletMap.get(jwc);
  625. if (userWallet != null) {
  626. result.add(userWallet);
  627. }
  628. }
  629. // 第五步:构建并返回 PageInfo
  630. PageInfo<UserWalletVO> resultPageInfo = new PageInfo<>(result);
  631. resultPageInfo.setTotal(jwcodePageInfo.getTotal());
  632. resultPageInfo.setPages(jwcodePageInfo.getPages());
  633. resultPageInfo.setPageNum(pageNum);
  634. resultPageInfo.setPageSize(pageSize);
  635. return resultPageInfo;
  636. }
  637. //新增流水--其他收入
  638. @Override
  639. public String addExFund(CashCollection addFundsDTO) {
  640. if (addFundsDTO.getPerformanceMarket() == null|| addFundsDTO.getPerformanceMarket().isEmpty())
  641. throw new IllegalArgumentException("业绩归属地区不能为空");
  642. if (addFundsDTO.getGoodsName() == null|| addFundsDTO.getGoodsName().isEmpty())
  643. throw new IllegalArgumentException("收入类别不能为空");
  644. if (addFundsDTO.getPayType() == null|| addFundsDTO.getPayType().isEmpty())
  645. throw new IllegalArgumentException("付款方式不能为空");
  646. if (addFundsDTO.getPaymentCurrency() == null)
  647. throw new IllegalArgumentException("币种不能为空");
  648. if (addFundsDTO.getPaymentAmount() == null)
  649. throw new IllegalArgumentException("付款金额不能为空");
  650. if (addFundsDTO.getGoodNum() == null)
  651. addFundsDTO.setGoodNum(0);
  652. //生成订单号后半部分
  653. String orderNumber = UUID.randomUUID().toString().replaceAll("-", "");
  654. //构建订单信息
  655. addFundsDTO.setOrderCode("QT_" + orderNumber); //订单号
  656. addFundsDTO.setStatus(4);
  657. addFundsDTO.setActivity("123");
  658. addFundsDTO.setJwcode(90039082);
  659. addFundsDTO.setName("HomilyLink");
  660. addFundsDTO.setMarket("24032");
  661. addFundsDTO.setOrderType(1);
  662. addFundsDTO.setReceivedMarket(addFundsDTO.getPerformanceMarket());
  663. addFundsDTO.setReceivedAmount(addFundsDTO.getPaymentAmount());
  664. addFundsDTO.setReceivedCurrency(addFundsDTO.getPaymentCurrency());
  665. cashCollectionMapper.addExFund(addFundsDTO);
  666. return "添加成功";
  667. }
  668. //添加iPay88手续费
  669. @Override
  670. public String addIpay88Fee(CashCollection cashCollection) {
  671. if (cashCollection.getPayType()== null|| cashCollection.getPayType().isEmpty())
  672. throw new IllegalArgumentException("支付方式不能为空");
  673. if (cashCollection.getPerformanceMarket()== null|| cashCollection.getPerformanceMarket().isEmpty())
  674. throw new IllegalArgumentException("业绩归属地区不能为空");
  675. if (cashCollection.getPaymentCurrency()== null|| cashCollection.getPaymentCurrency().isEmpty())
  676. throw new IllegalArgumentException("币种不能为空");
  677. if (cashCollection.getHandlingCharge()== null|| cashCollection.getHandlingCharge().compareTo(BigDecimal.ZERO) < 0)
  678. throw new IllegalArgumentException("手续费不能为空");
  679. if (cashCollection.getRemark()== null|| cashCollection.getRemark().isEmpty())
  680. throw new IllegalArgumentException("备注不能为空");
  681. //生成订单号后半部分
  682. String orderNumber = UUID.randomUUID().toString().replaceAll("-", "");
  683. //构建订单信息
  684. cashCollection.setOrderCode("QT_" + orderNumber); //订单号
  685. cashCollection.setGoodsName("手续费");
  686. cashCollection.setReceivedMarket("5");
  687. cashCollection.setStatus(4);
  688. cashCollection.setPaymentAmount(BigDecimal.ZERO);
  689. cashCollection.setJwcode(90039082);
  690. cashCollection.setName("HomilyLink");
  691. cashCollection.setMarket("24032");
  692. cashCollection.setOrderType(1);
  693. cashCollection.setActivity("124");
  694. cashCollectionMapper.addIpay88Fee(cashCollection);
  695. return "添加成功";
  696. }
  697. @Override
  698. public void adjust(PerformanceAdjustmentDTO adjustDTO) {
  699. if (adjustDTO == null) {
  700. throw new IllegalArgumentException("传参不能为空");
  701. }
  702. int[][] matrix = adjustDTO.getMatrix();
  703. Double weight = adjustDTO.getWeight();
  704. if (weight == null) {
  705. throw new IllegalArgumentException("权重不能为空");
  706. }
  707. // Performance market codes and corresponding Chinese names
  708. String[] performanceMarkets = {"4", "5", "13", "24018", "24022", "24016"};
  709. String[] marketNames = {"新加坡", "马来西亚", "香港", "泰国", "越南", "加拿大"};
  710. // Multiply each element in the matrix by the factor
  711. for (int i = 0; i < matrix.length; i++) {
  712. for (int j = 0; j < matrix[i].length; j++) {
  713. // Calculate adjusted value and round to nearest integer
  714. int adjustedValue = (int) (matrix[i][j] * weight);
  715. matrix[i][j] = adjustedValue;
  716. if (i == j) {
  717. continue;
  718. }
  719. // Skip if value is 0
  720. if (adjustedValue == 0) {
  721. continue;
  722. }
  723. // Create order code with timestamp
  724. String orderCode = "TZ_" + System.currentTimeMillis();
  725. // Determine direction and create remark based on value sign
  726. String fromMarket = performanceMarkets[i];
  727. String toMarket = performanceMarkets[j];
  728. String fromName = marketNames[i];
  729. String toName = marketNames[j];
  730. String remark;
  731. if (adjustedValue > 0) {
  732. // Positive value: row to column (转出方 to 转入方)
  733. remark = fromName + "→" + toName + "调整金额:" + adjustedValue;
  734. } else {
  735. // Negative value: column to row (转入方 to 转出方)
  736. remark = toName + "→" + fromName + "调整金额:" + -adjustedValue;
  737. }
  738. // Create CashRecord objects and call mapper adjust method twice
  739. for (int k = 0; k < 2; k++) {
  740. CashRecord cashRecord = new CashRecord();
  741. cashRecord.setOrderCode(orderCode + "_" + k);
  742. cashRecord.setSubmitterId(adjustDTO.getSubmitterId());
  743. cashRecord.setSubmitterMarket(adjustDTO.getSubmitterMarket());
  744. cashRecord.setRemark(remark);
  745. cashRecord.setPayTime(adjustDTO.getTime());
  746. if(k == 0){
  747. cashRecord.setPerformanceMarket(fromMarket);
  748. cashRecord.setReceivedMarket(fromMarket);
  749. cashRecord.setReceivedAmount(new BigDecimal(-adjustedValue));
  750. }else{
  751. cashRecord.setPerformanceMarket(toMarket);
  752. cashRecord.setReceivedMarket(toMarket);
  753. cashRecord.setReceivedAmount(new BigDecimal(adjustedValue));
  754. }
  755. // Call mapper adjust method
  756. cashCollectionMapper.adjust(cashRecord);
  757. }
  758. }
  759. }
  760. }
  761. /**
  762. * 校验钱包 ID 和到账地区的对应关系
  763. * @param walletId 钱包 ID
  764. * @param receivedMarket 到账地区 ID
  765. */
  766. private void validateWalletAndMarket(Integer walletId, String receivedMarket) {
  767. if (walletId == null) {
  768. return; // 非金币充值不需要校验
  769. }
  770. Map<Integer, String> walletMarketMap = new HashMap<>();
  771. walletMarketMap.put(2, "13"); // 香港
  772. walletMarketMap.put(3, "4"); // 新加坡 HC
  773. walletMarketMap.put(4, "5"); // 马来西亚
  774. walletMarketMap.put(5, "4"); // 新加坡 CM
  775. walletMarketMap.put(6, "24016"); // 加拿大
  776. walletMarketMap.put(7, "24018"); // 泰国 HS
  777. walletMarketMap.put(8, "24018"); // 泰国 HA
  778. walletMarketMap.put(9, "24022"); // 越南 HCM
  779. walletMarketMap.put(10, "24033");// 北京
  780. // 钱包 ID=1 为历史钱包,无限制,不需要校验
  781. if (walletId == 1) {
  782. return;
  783. }
  784. String expectedMarket = walletMarketMap.get(walletId);
  785. if (expectedMarket == null) {
  786. throw new IllegalArgumentException("无效的钱包 ID: " + walletId);
  787. }
  788. if (!expectedMarket.equals(receivedMarket)) {
  789. String marketName = marketMapper.getMarketNameById(expectedMarket);
  790. throw new IllegalArgumentException("钱包 ID=" + walletId + " 对应的到账地区应为:" + marketName + "(" + expectedMarket + ")");
  791. }
  792. }
  793. }